Count distinct occurrences of items among multiple columns in a pattern - php

I am working on a survey application using MySql and PHP
The responses will be in the following format:
+-c1_1-+-c1_2-+-c1_3-+-c1_1-+-c1_2-+-c1_3-+-....
+ red + blue + pink + cyan + red + gray + ....
+ black+ pink + plum + red + blue + gray + ....
+ cyan + red + blue + blue + pink + plum + ....
+------+------+------+------+------+------+ ....
c1_1 represents Column_For_Question_1_With_Rank_1
c1_2 represents Column_For_Question_1_With_Rank_2
c1_3 represents Column_For_Question_1_With_Rank_3
c2_1 represents Column_For_Question_2_With_Rank_1
c2_2 represents Column_For_Question_2_With_Rank_2
c2_3 represents Column_For_Question_2_With_Rank_3
Scoring is like this:
Rank 1 = color in column cX_1 = gets 3 marks (c1_1,c2_1,c3_1..)
Rank 2 = color in column cX_2 = gets 2 marks (c1_2,c2_2,c3_2..)
Rank 3 = color in column cX_3 = gets 1 mark (c1_3,c2_3,c3_3..)
Score of Red:
appears in cX_1 two time = 3x2=6
appears in cX_2 two times = 2x2=4
So Red gets a score of 6+4=10
Score of Blue:
appears in cX_1 one time = 3x1=3
appears in cX_2 two times = 2x2=4
appears in cX_3 two times = 1x2=2
So blue gets a score of 3+4+2 = 9
Is it possible to write an effective query to arrive at a result like:
+-color-+-score-+
+ red + 10 +
+ blue + 9 +
+ xxx + # +
+ xxx + # +
+ xxx + # +
+-------+-------+
If that is not possible, atleast the number of occurances like:
+-color-+-n_cX_1-+-n_cX_2-+-n_cX_3-+
+ red + 2 + 2 + 0 +
+ blue + 1 + 2 + 2 +
+ xxx + # + # + # +
+ xxx + # + # + # +
+ xxx + # + # + # +
+ xxx + # + # + # +
+-------+--------+--------+--------+
Actually the colors will be replaced by people names.
Each 'set of three consecutive columns' (cX_1,cX_2,cX_3) represent first, second and third ranks rated for each of 9 questions. So there will be 3x9=27 columns
Can someone please help me with this? I am thinking on using count(*) repeatedly but I am sure it is a wrong approach. Searched a lot before posting but could not solve it.
Edit 1:
Want to mention that there might be almost 50 people names in these columns. And each row would represent response from one examiner doing the survey. There will be about 100 such examiners and hence about 100 rows.

Here is my solution, i am messing with PHP more, so my answer will be by PHP side, if you want SQL solution, you should wait for some time to let another user add SQL side solution,
You will get this kind of array in PHP from MySQL,
$result = [
'c1_1'=>['red','black','cyan'],
'c1_2'=>['blue','pink','red'],
'c1_3'=>['pink','plum','blue'],
'c2_1'=>['cyan','red','blue'],
'c2_2'=>['red','blue','pink'],
'c2_3'=>['gray','gray','plum']
];
Now, generate an users array having each user's achievements in each category,
$users = [];
foreach($result as $k => $v)
{
foreach($v as $user)
{
$users[$user][] = $k;
}
}
Now, $users array will look like,
array (size=7)
'red' =>
array (size=4)
0 => string 'c1_1' (length=4)
1 => string 'c1_2' (length=4)
2 => string 'c2_1' (length=4)
3 => string 'c2_2' (length=4)
'black' =>
array (size=1)
0 => string 'c1_1' (length=4)
'cyan' =>
array (size=2)
0 => string 'c1_1' (length=4)
1 => string 'c2_1' (length=4)
'blue' =>
array (size=4)
0 => string 'c1_2' (length=4)
1 => string 'c1_3' (length=4)
2 => string 'c2_1' (length=4)
3 => string 'c2_2' (length=4)
'pink' =>
array (size=3)
0 => string 'c1_2' (length=4)
1 => string 'c1_3' (length=4)
2 => string 'c2_2' (length=4)
'plum' =>
array (size=2)
0 => string 'c1_3' (length=4)
1 => string 'c2_3' (length=4)
'gray' =>
array (size=2)
0 => string 'c2_3' (length=4)
1 => string 'c2_3' (length=4)
Now, define a function to calculate marks, by passing the array by user we just generated,
function marks_of($input)
{
$marks_index = ['_1'=>3, '_2'=>2, '_3'=>1]; // define marks here
$marks = 0;
foreach($input as $marking)
{
$marks += $marks_index[substr($marking, -2)];
}
return $marks;
}
You need to define marks in each category as i commented in the above code.
Now, use it like,
$marks_of_red = marks_of($users['red']);
will give
int 10
To generate an array having each user's marks by name,
$all_users_marks = [];
foreach($users as $name => $achievements)
{
$all_users_marks[$name] = marks_of($users[$name]);
}
Now, $all_users_marks is
array (size=7)
'red' => int 10
'black' => int 3
'cyan' => int 6
'blue' => int 8
'pink' => int 5
'plum' => int 2
'gray' => int 2
As i already said, wait for someone if you want MySQL sided answer.

Normalize the table like this:
question | rank | name
Then use this query to get the total scores:
SELECT name, SUM( 4 - rank ) score FROM mytable GROUP BY name ORDER BY score DESC

Related

GFS Grib Wind Values Decode And Convert (U & V)

Im doing a Grib2 decoder in PHP, and started with a half written library that I found. Everything is working fine except the values I get from the data are incorrect after converting Int Values to real values. I think I am converting everything right, and even when I test with cloud data it looks correct when I check it in Panoply. I think its with this formula that is all over the internet. Below im using 10 m above ground GFS from https://nomads.ncep.noaa.gov
Y*10^D = R+(X1+X2)*2^E
Im not sure I'm plugging in the values correctly but again it works with cloud cover percentages.
So.... The "Data Representation Values" I get from Grib Section 5
'Reference value (R)' => 886.25067138671875,
'Binary Scale Factor (E)' => 0,
'Decimal Scale Factor (D)' => 2,
'Number of bits used for each packed value' => 11,
'exp' => pow(2, $E), //(Equals 1) (The Library used these as the 2^E)
'base' => pow(10, $D), //(Equals 100) (And the 10^D)
'template' => 0,
As you can see below the numbers definitely have a connection to the Reference Value. The Number closest to 886(R) is 892 and its actual value should be 0.05 as shown below (EX.) The numbers Higher are than 892 are positive and the ones lower than 892 are negative. But when I user the formula (886 + 892 * 1) / 100 it give me 17.78, not 0.05. I seem to be missing something pretty obvious, am I misunderstanding the formula/equation where Y is the value I want...
X1 = 0 (documentation says)
X2 = 892 (documentation says is scaled value, the value in the Grib from bits?)
2^0 = 1
10^2 = 100
R = 886.25067138671875
Y * 10^D = R + (X1 + X2) * 2^E
Y * 100 = R + (X1 + X2) * 1
886 + (0 + 892) * 1 ) / 100
(886 + 892 * 1) / 100
= 17.78
Int Values of wind from Grib (After converting from Bits)
0 => 695,
1 => 639,
2 => 631,
3 => 0,
4 => 436,
5 => 513,
6 => 690,
7 => 570,
8 => 625,
9 => 805,
10 => 892,<-----------(EX.)
11 => 1044,
12 => 952,
13 => 1081,
14 => 1414,
15 => 997,
16 => 1106,
17 => 974,
18 => 1135,
19 => 1069,
20 => 912,
Actual decoded wind values shown in Panoply (Well known Grib App)
-1.9125067
-2.4725068
-2.5525067
-8.862507
-4.5025067
-3.7325068
-1.9625068
-3.1625068
-2.6125066
-0.81250674
0.057493284 <-----------(EX.)
1.5774933
0.6574933
1.9474933
5.2774935
1.1074933
2.1974933
0.87749326
2.4874933
1.8274933
0.2574933
y = 0.01 * (x - 886.25067138671875) seems to work for all points
so 0.01 * (892 - 886.25067138671875) = 0.0574

How to limit a variable search to a single line of text?

Considering this sample text:
grupo1, tiago1A, bola1A, mola1A, tijolo1A, pedro1B, bola1B, mola1B, tijolo1B, raimundo1C, bola1C, mola1C, tijolo1C, joao1D, bola1D, mola1D, tijolo1D, felipe1E, bola1E, mola1E, tijolo1E,
grupo2, tiago2A, bola2A, mola2A, tijolo2A, pedro2B, bola2B, mola2B, tijolo2B, raimundo2C, bola2C, mola2C, tijolo2C, joao2D, bola2D, mola2D, tijolo2D, felipe2E, bola2E, mola2E, tijolo2E,
grupo3, tiago3A, bola3A, mola3A, tijolo3A, pedro3B, bola3B, mola3B, tijolo3B, raimundo3C, bola3C, mola3C, tijolo3C, joao3D, bola3D, mola3D, tijolo3D, felipe3E, bola3E, mola3E, tijolo3E,
grupo4, tiago4A, bola4A, mola4A, tijolo4A, pedro4B, bola4B, mola4B, tijolo4B, raimundo4C, bola4C, mola4C, tijolo4C, joao4D, bola4D, mola4D, tijolo4D, felipe4E, bola4E, mola4E, tijolo4E,
grupo5, tiago5A, bola5A, mola5A, tijolo5A, pedro5B, bola5B, mola5B, tijolo5B, raimundo5C, bola5C, mola5C, tijolo5C, joao5D, bola5D, mola5D, tijolo5D, felipe5E, bola5E, mola5E, tijolo5E,
I would like to capture the 20 values that follow grupo3 and store them in groups of 4.
I am using this: (Demo)
/grupo3,((.*?),(.*?),(.*?),(.*?)),/
but this only returns the first 4 comma separated values after grupo3.
I need generate this array structure:
Match 1
Group 1 tiago3A
Group 2 bola3A
Group 3 mola3A
Group 4 tijolo3A
Match 2
Group 1 pedro3B
Group 2 bola3B
Group 3 mola3B
Group 4 tijolo3B
Match 3
Group 1 raimundo3C
Group 2 bola3C
Group 3 mola3C
Group 4 tijolo3C
Match 4
Group 1 joao3D
Group 2 bola3D
Group 3 mola3D
Group 4 tijolo3D
Match 5
Group 1 felipe3E
Group 2 bola3E
Group 3 mola3E
Group 4 tijolo3E
You can try the following:
/,(.*?),(.*?),(.*?),(.*?),.*?$/m
the /m in the end indicates the flag for multi-line and $ before that indicates end of line. Demo
Edit: For getting every 4 elements only form the 3rd paragraph
/grupo3,((.*?),(.*?),(.*?),(.*?)), ((.*?),(.*?),(.*?),(.*?)), ((.*?),(.*?),(.*?),(.*?)), ((.*?),(.*?),(.*?),(.*?)), ((.*?),(.*?),(.*?),(.*?)),/
Demo
And you can get the desired output in PHP like:
preg_match('/grupo3,((.*?),(.*?),(.*?),(.*?)), ((.*?),(.*?),(.*?),(.*?)), ((.*?),(.*?),(.*?),(.*?)), ((.*?),(.*?),(.*?),(.*?)), ((.*?),(.*?),(.*?),(.*?)),/', $str, $matches);
$groups = [];
unset($matches[0]);
$matches = array_values($matches);
$count = count($matches);
$j=0;
for($i=1;$i<$count;$i++)
{
if($i%5 == 0)
{
$j++;
continue;
}
$groups[$j][] = $matches[$i];
}
var_dump($groups);
Output will be something like:
array (size=5)
0 =>
array (size=4)
0 => string ' tiago3A' (length=8)
1 => string ' bola3A' (length=7)
2 => string ' mola3A' (length=7)
3 => string ' tijolo3A' (length=9)
1 =>
array (size=4)
0 => string 'pedro3B' (length=7)
1 => string ' bola3B' (length=7)
2 => string ' mola3B' (length=7)
3 => string ' tijolo3B' (length=9)
2 =>
array (size=4)
0 => string 'raimundo3C' (length=10)
1 => string ' bola3C' (length=7)
2 => string ' mola3C' (length=7)
3 => string ' tijolo3C' (length=9)
3 =>
array (size=4)
0 => string 'joao3D' (length=6)
1 => string ' bola3D' (length=7)
2 => string ' mola3D' (length=7)
3 => string ' tijolo3D' (length=9)
4 =>
array (size=4)
0 => string 'felipe3E' (length=8)
1 => string ' bola3E' (length=7)
2 => string ' mola3E' (length=7)
3 => string 'tijolo3E' (length=0)
Please forgive the lateness of this answer. This is the comprehensive answer with a clean/direct solution that I would have posted earlier if this page wasn't put on hold. This is as refined a solution as I can devise without knowing more about how your input data is generated/accessed.
The input:
$text='grupo1, tiago1A, bola1A, mola1A, tijolo1A, pedro1B, bola1B, mola1B, tijolo1B, raimundo1C, bola1C, mola1C, tijolo1C, joao1D, bola1D, mola1D, tijolo1D, felipe1E, bola1E, mola1E, tijolo1E,
grupo2, tiago2A, bola2A, mola2A, tijolo2A, pedro2B, bola2B, mola2B, tijolo2B, raimundo2C, bola2C, mola2C, tijolo2C, joao2D, bola2D, mola2D, tijolo2D, felipe2E, bola2E, mola2E, tijolo2E,
grupo3, tiago3A, bola3A, mola3A, tijolo3A, pedro3B, bola3B, mola3B, tijolo3B, raimundo3C, bola3C, mola3C, tijolo3C, joao3D, bola3D, mola3D, tijolo3D, felipe3E, bola3E, mola3E, tijolo3E,
grupo4, tiago4A, bola4A, mola4A, tijolo4A, pedro4B, bola4B, mola4B, tijolo4B, raimundo4C, bola4C, mola4C, tijolo4C, joao4D, bola4D, mola4D, tijolo4D, felipe4E, bola4E, mola4E, tijolo4E,
grupo5, tiago5A, bola5A, mola5A, tijolo5A, pedro5B, bola5B, mola5B, tijolo5B, raimundo5C, bola5C, mola5C, tijolo5C, joao5D, bola5D, mola5D, tijolo5D, felipe5E, bola5E, mola5E, tijolo5E,';
The method: (PHP Demo)
var_export(preg_match('/^grupo3, \K.*(?=,)/m',$text,$out)?array_chunk(explode(', ',$out[0]),4):'fail');
Use preg_match() to extract the single line, then use explode() to split the string on "comma space", then use array_chunk() to store in an array of 5 subarrays containing 4 elements each.
The pattern targets grupo3, at the start of the line, then restarts the full match using \K then greedily matches every non-newline character and stops just before the last comma in the line. The positive lookahead (?=,) doesn't store the final comma in the full string match.
(Pattern Demo)
My method does not retain any leading and trailing spaces, just the values themselves.
Output:
array (
0 =>
array (
0 => 'tiago3A',
1 => 'bola3A',
2 => 'mola3A',
3 => 'tijolo3A',
),
1 =>
array (
0 => 'pedro3B',
1 => 'bola3B',
2 => 'mola3B',
3 => 'tijolo3B',
),
2 =>
array (
0 => 'raimundo3C',
1 => 'bola3C',
2 => 'mola3C',
3 => 'tijolo3C',
),
3 =>
array (
0 => 'joao3D',
1 => 'bola3D',
2 => 'mola3D',
3 => 'tijolo3D',
),
4 =>
array (
0 => 'felipe3E',
1 => 'bola3E',
2 => 'mola3E',
3 => 'tijolo3E',
),
)
p.s. If the search term ($needle) is to be dynamic, you can use something like this to achieve the same result: (PHP Demo)
$needle='grupo3';
// if the needle may include any regex-sensitive characters, use preg_quote($needle,'/') at $needle
var_export(preg_match('/^'.$needle.', \K.*(?=,)/m',$text,$out)?array_chunk(explode(', ',$out[0]),4):'fail');
/* or this is equivalent...
if(preg_match('/^'.$needle.', \K.*(?=,)/m',$text,$out)){
$singles=explode(', ',$out[0]);
$groups=array_chunk($singles,4);
var_export($groups);
}else{
echo 'fail';
}
*/

Display php array on a fix html table without affecting the number of rows

I am still in the process of learning PHP and would like to seek for your assistance regarding my concern. I already know how to display an array into an html table which i usually do with my forms. Then suddenly i came into this issue wherein there should be a fix table with a fix number of rows (lets say about 5 rows).
Now if i would display information coming from a specific user and that user only has 2 rows of data from mysql then i will only have 2 rows displayed on my html table.
What happens:
*****************
** A ** B ** C **
*****************
** 1 ** 2 ** 3 **
*****************
** 4 ** 5 ** 6 **
*****************
What i want as an output:
*****************
** A ** B ** C **
*****************
** 1 ** 2 ** 3 **
*****************
** 4 ** 5 ** 6 **
*****************
** ** ** **
*****************
** ** ** **
*****************
Is there a neat way to code this. Your idea is already a big help; I am not asking for codes but you can somehow guide me on what i can do here in order to achieve the output i want.
Thanks.
You could maintain a second counter with your fixed number calculations. In pseudo-code, it might look like this:
$rowCount = 0;
while (getNextDataRow()) {
printDataRow();
$rowCount++;
}
while ($rowCount <= 5) {
printEmptyRow();
$rowCount++;
}
Note that this would add empty rows when needed, but it wouldn't constrain the number of rows if the data contains more than 5. It's up to you what to do in that case. The data query could have a LIMIT to prevent that from happening, the first while loop could have a check for $rowCount == 5 and exit the loop, etc.
Use a for loop with an if statement. Something like this:
$myData = array(
array('A', 'B', 'C'),
array('1', '2', '3'),
array('4', '5', '6')
);
for ($i = 0; $i < 5; $i++)
{
echo '<tr>';
if (isset($myData[$i]))
{
echo '<td>'.$myData[$i][0].'</td>';
echo '<td>'.$myData[$i][1].'</td>';
echo '<td>'.$myData[$i][2].'</td>';
}
else
{
echo '<td> </td>';
echo '<td> </td>';
echo '<td> </td>';
}
echo '</tr>';
}
You can fill your array with empty strings till its count is 5:
$array = array(array(1,2,3),array(4,5,6));
for($i=0, $add = 5-count($array);$i<$add;$i++){
$array[]=array('','','');
}
var_dump($array);
Output:
array (size=5)
0 =>
array (size=3)
0 => int 1
1 => int 2
2 => int 3
1 =>
array (size=3)
0 => int 4
1 => int 5
2 => int 6
2 =>
array (size=3)
0 => string '' (length=0)
1 => string '' (length=0)
2 => string '' (length=0)
3 =>
array (size=3)
0 => string '' (length=0)
1 => string '' (length=0)
2 => string '' (length=0)
4 =>
array (size=3)
0 => string '' (length=0)
1 => string '' (length=0)
2 => string '' (length=0)

Replace mysql coloumn values when adding them to an php array

I have a table called "Current state", it has three columns known as:
id name state
1 FXD 1
2 GFX 3
3 ATOM 2
4 FARB 3
5 REX 1
6 FRX 2
In the following code I get it into array and print it:
$exc = $conn->prepare("SELECT name,state from current_state");
$exc->execute();
while($finalResult = $exc->fetch(PDO::FETCH_ASSOC))
{
$tables[] = $finalResult;
}
var_dump($tables);
But the problem is though numbers represent the state column values each of those numbers have a meaning:
1 = running
2 = finished
3 = dimnished
So what I want is to add the above string values right away to the tables array by comparing the values of the state column.
The current print result of a column would look like
array (size=2)
'name' => string 'FRX' (length=11)
'state' => string '2' (length=1)
But what I want is:
array (size=2)
'name' => string 'FRX' (length=11)
'state' => string 'finished' (length=8)
You can either do it in SQL with a CASE expression:
SELECT name,
CASE state
WHEN 1 THEN 'running'
WHEN 2 THEN 'finished'
WHEN 3 THEN 'diminished'
END AS state
FROM current_state
Or you could do it in PHP with an array:
$statemap = array(1 => 'running', 2 => 'finished', 3 => 'diminished');
Then your PHP loop would do the mapping:
while ($finalResult = $exc->fetch(PDO::FETCH_ASSOC)) {
$finalResult['state'] = $statemap[$finalResult['state']];
$tables[] = $finalResult;
}
Finally, you could have another table that contains the mappings, and join with it:
CREATE TABLE state_mappings (
state_num INT PRIMARY KEY,
state_name VARCHAR(20)
);
SELECT name, state_name
FROM state AS s
JOIN state_mappings AS m ON s.state = m.state_num

Mysql row into array PHP

This question has already been asked tons of times, but I can't really understand how to do this.
I'm trying to insert the values of an entire row, into an array in PHP.
Here is the query result:
+-----+-----+------+------+------+------+------+-----+
+ Ln1 + Ln2 + Mar1 + Mar2 + Mar3 + Mer1 + Mer2 + Mer3+
+-----+-----+------+------+------+------+------+-----+
+ 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 +
+-----+-----+------+------+------+------+------+-----+
I would like to insert all those '1' into an array called $giorni, actually I'm using
$arr_prep= array("Ln1","Ln2","Mar1","Mar2","Mar3","Mer1","Mer2","Mer3");
$giorni = array();
for($c = 0; $c < 8; $c++){
$temp = mysql_fetch_array(mysql_query("SELECT '$arr_prep[$c]' FROM Corsi WHERE id='$id'"));
array_push($giorni,$temp);
}
And the result printed with "echo "giorni -->".array_values($giorni);" is:
giorni -->Arraygiorni -->Arraygiorni -->Arraygiorni -->Arraygiorni -->Arraygiorni -->Arraygiorni -->Arraygiorni -->Array
I've also tried with mysql_fetch_array and mysql_fetch_row, maybe I'm using them in the wrong way but I could not make it work.
Can anyone suggest me how to do it?
Thanks
Try Changing SELECT '$arr_prep[$c]' FROM... to SELECT $arr_prep[$c] FROM..
Remove ''
you'll get output as
Array ( [0] => 1 1 => 1 [2] => 1 [3] => 1 [4] => 1 [5] => 1 [6] => 1 [7] => 1 )

Categories