I am trying to query mysql db using values passed in an array. The problem is the first element produces two results. Here is my code and results.
$common = array_intersect($ingredients, $ingredients2);
unset($common['1']);
$unique = array_unique($common);
echo "The common array is:";
print_r(array_count_values($common));
echo "<br> The unique array is :";
print_r($unique);
echo "<br>";
echo extract($unique)."<br>";
$i = 0;
$sum = 0;
foreach (array_count_values($common) as $key => $value) {
$keys = "$key";
$value = "$value";
echo "$keys : ";
echo "$value<br>";
$i++;
$sql = mysql_query("SELECT * FROM `ingredients` WHERE `name` = '$keys'") or die(mysql_error());
while ($row = mysql_fetch_array($sql)) {
$price = $row['price'];
echo "The price is : $price<br>";
$total_price = $value*$price;
echo "The total price for $keys is : $total_price<br>";
$sum+= $total_price;
}
}
echo "The sum of the prices is $sum";
Here is what I get:
The common array is:Array ( [test] => 3 [ugali] => 2 [mboga] => 2 [0] => 1 )
The unique array is :Array ( [0] => test [2] => ugali [4] => mboga [8] => 0 )
0
test : 3
The price is : 100
The total price for test is : 300
The price is : 100
The total price for test is : 300
ugali : 2
The price is : 100
The total price for ugali is : 200
mboga : 2
The price is : 4
The total price for mboga is : 8
0 : 1
The sum of the prices is 808
I got the answer to this. I removed the while loop and it worked instead of
while ($row = mysql_fetch_array($sql)) {}
I have
$row = mysql_fetch_array($sql);
That solved the problem.
Related
I need to read, line aligns and group by (Cd), which is the only index of each record. Thus, (Cd) refers to each new record, which may contain several sub groups: (11), (22), (Co), etc. These sub groups may contain an additional line (see example of (Co) in the first record, which should concatenate the lines containing "for cabinet" and "for closet.").
My TXT file structure, is this:inventory.txt
>No. 0012 of 01/31/2016
>No. 0012 of 01/31/2016
>(Cd) 12345
>(11) Cod1-023
>(22) 22/12/1945
>(Co) locking doors
>For cabinet
>For closet.
>(Cd) 23456
>(11) Cod1-055
>(21) 01/01/2005
>(22) drawer iron
>,wood
>,aluminum
>(Cd) 78920
>(22) Cod1-077
>(54) 2/22/1975
>(Co) clip Aluminum or iron
>(74) anodized
>(Cd) 0002525
>(Di) Cod4-07100
>(11) 02/22/2017
>(22) shirt Red green
>(54) yellow buttons
>(Co) mango
>,avocado
>,cherry
I implemented the following routine but, after much research and modifications, I was not able to group the sub indices:
Together, I need a routine to transfer the data from the array to variables and, later, to the mysql DB.
If anyone can give me a light, thank you.
$cd = [];
$group = [];
$counter = 0;
$file = fopen ('inventory.txt', 'r');
while (! feof ($file)) {
$row = trim (fgets ($file, 1024));
// $row = trim ($row);
if (substr ($row, 0, 4) == '(cd)') {
$counter = 0;
if (! empty ($group)) {
$cd [$id] = $group;
$group = [];
$counter = 0;
}
$id = substr ($row, 5, strlen ($row) -5);
$cd [$id] [] = $line;
} else {
if (substr ($row, 0, 4)! == '(11)') {
if (isset ($group [$counter-1])) {
$group [$counter -1]. = ''. $line;
$counter--;
}
} else {
$group [] = $row;
}
$counter ++;
}
}
$cd [$id] = $group;
fclose ($file);
echo '<pre>';
print_r ($cd);
exit;
// -------------------------
// routine to transfer data from array to variables
$keys = array_keys ($cd);
for ($i = 0; $i <count ($cd); $i ++) {
echo $keys [$i]. "<br>";
foreach ($cd [$keys [$i]] as $key => $value) {
echo $key. ":". $value. "<br>";
}
echo "<br>";
}
Thank you for editing your question to attach the file content rows. Here is my new solution.
This will disallow concatenation for any lines immediately after a (22) line.
If there are other triggers beyond (22) that should indicate concatenation is unwanted, modify the $concat condition in the second elseif block.
$cd=[]; // declare array
$i=-1; // set outer index
$concat=true;
$file=fopen('inventory.txt','r');
while(!feof($file)){
$row=trim(fgets($file,1024));
if(preg_match('/^\(Cd\)\s(.+)/',$row,$match)){ // capture Cd numbers
++$i; // increment outer_index
$j=-1; // reset inner_index
$id=$match[1]; // store cd value
$concat=true;
}elseif(preg_match('/^(\(..\)\s.*)/',$row,$match)){ // capture Cd data
++$j; // this is a new innerarray element, increment its index
$cd[$i][$id][$j]=$match[1]; // push element into array
$concat=(strpos($match[1],'(22)')!==0?true:false);
}elseif(isset($id) && $concat){ // ignore all file header content
$cd[$i][$id][$j].=" $row"; // concatenate to last element
}
}
echo "<pre>";
var_export($cd); // display in true nested form
echo "</pre>";
foreach($cd as $outer_index=>$cdarrays){
foreach($cdarrays as $id=>$innerarrays){
foreach($innerarrays as $inner_index=>$line){
echo "$outer_index : $id : $inner_index = $line<br>"; // display keys & values by row
}
}
}
The $cd array will have this structure:
array (
0 =>
array (
12345 =>
array (
0 => '(11) Cod1-023',
1 => '(22) 22/12/1945',
2 => '(Co) locking doors For cabinet For closet. ',
),
),
1 =>
array (
23456 =>
array (
0 => '(11) Cod1-055',
1 => '(21) 01/01/2005',
2 => '(22) drawer iron',
),
),
2 =>
array (
78920 =>
array (
0 => '(22) Cod1-077',
1 => '(54) 2/22/1975',
2 => '(Co) clip Aluminum or iron',
3 => '(74) anodized',
),
),
3 =>
array (
'0002525' =>
array (
0 => '(Di) Cod4-07100',
1 => '(11) 02/22/2017',
2 => '(22) shirt Red green',
3 => '(54) yellow buttons',
4 => '(Co) mango ,avocado ,cherry',
),
),
)
Or if you want to view it in a flattened/verbose style:
0 : 12345 : 0 = (11) Cod1-023
0 : 12345 : 1 = (22) 22/12/1945
0 : 12345 : 2 = (Co) locking doors For cabinet For closet.
1 : 23456 : 0 = (11) Cod1-055
1 : 23456 : 1 = (21) 01/01/2005
1 : 23456 : 2 = (22) drawer iron
2 : 78920 : 0 = (22) Cod1-077
2 : 78920 : 1 = (54) 2/22/1975
2 : 78920 : 2 = (Co) clip Aluminum or iron
2 : 78920 : 3 = (74) anodized
3 : 0002525 : 0 = (Di) Cod4-07100
3 : 0002525 : 1 = (11) 02/22/2017
3 : 0002525 : 2 = (22) shirt Red green
3 : 0002525 : 3 = (54) yellow buttons
3 : 0002525 : 4 = (Co) mango ,avocado ,cherry
#mickmackusa I have much to thank for your patience and contribution. His code was excellent, but he was eliminating the lines he was leaping (22). So, I modified the structure to capture the values of those following, including in a new ID inside the array.
My array knowledge is very limited, but the code is functional for my needs.
In case you can contribute to simplify the operation that I built, I'm happy to know.
Why error Occurs "Warning: Undefined offset: 3 and Undefined offset: 5, in this line: $cd[$i][$id][$j]. = "$Row";
$cd=[]; // declare array
$trash=[];
$i=-1; // set outer index
$concat=true;
$file=fopen('inventory.txt','r');
while(!feof($file)){
$row=trim(fgets($file,1024));
if(preg_match('/^\(Cd\)\s(.+)/',$row,$match)){ // capture Cd numbers
++$i; // increment outer_index
$j=-1; // reset inner_index
$id=$match[1]; // store cd value
$concat=true;
$row_previous=false;
$row_ob=false;
}elseif(preg_match('/^(\(..\)\s.*)/',$row,$match)){ // capture Cd data
++$j; // this is a new innerarray element, increment its index
$cd[$i][$id][$j]=$match[1]; // push element into array
//$concat=(strpos($match[1],'(Co)')!==0?true:false);
If (substr($row, 0, 5) == '(Co) ') {
$row_previous=true;
}
}elseif(isset($id)){ // ignore all file header content
If (($row_previous == true)and ($row_ob !== true)){
++$j; //increment its index to insert variable value created for the additional lines
$row="(Ob) ". (trim($row)); //create pre value variable
$row_ob=true;
$cd[$i][$id][$j].="$row "; // concatenate to last element to new
}else{
$cd[$i][$id][$j].=" $row"; // concatenate to last element
}
}
}
echo "<pre>";
var_export($cd); // display in true nested form
echo "</pre>";
foreach($cd as $outer_index=>$cdarrays){
foreach($cdarrays as $id=>$innerarrays){
foreach($innerarrays as $inner_index=>$line){
echo "$outer_index : $id : $inner_index = $line<br>"; // display keys & values by row
}
}
}
I am still a novice at PHP scripting.
I have an Array
$students = array(1201=>94,1203=>94,1200=>91, 1205=>89, 1209=>83, 1206=>65, 1202=>41, 1207=>38,1208=>37, 1204=>37,1210=>94);
From the associative array, the key are the student's exam no and the values are the student's scores. Then I used the 2 inbult PHP functions array_keys and array_values to separate the exam nos from the scores.
$exam_nos=(array_keys($students));
$marks=(array_values($students));
Then I passed the $marks array through the code below:
$i=0;
$occurrences = array_count_values($marks);
$marks = array_unique($marks);
echo '<table border="1">';
foreach($marks as $grade) {
if($grade == end($marks))$i += $occurrences[$grade]-1;
echo str_repeat('<tr><td>'.$grade.': '.($i+1).'</td></tr>',$occurrences[$grade]);
$i += $occurrences[$grade];
}
echo '</table><br />';
output:
94: 1
94: 1
94: 1
91: 4
89: 5
83: 6
65: 7
41: 8
38: 9
37: 11
37: 11
And this is closer to what I want; to rank the scores such that if a tie is encountered, 1 or more positions are skipped, occurs at the end the position the items at the end are assigned a position equivalent toi the total number of ranked items. However, it would be much helpful if this could be done without separating the Array into 2 ...
Questions:
(1) I am pulling my hair how, from the $student array I could have something like:
Exam No Score Position
1201 94 1
1210 94 1
1203 94 1
1200 91 4
1205 89 5
1209 83 6
1206 65 7
1202 41 8
1207 38 9
1204 37 11
1208 37 11
(2) I would like to be able to pick any student by exam no and be able to echo or print out her position e.g
the student 1207 is number 9.
I think I need to capture the postions in a variable, but how do I capture them? Well I don't know!
Could the experts help me here with a better way to achieve my 2 goals (please see questions 1 and 2)? I will try any suggestion that will help me disolve the 'metal blockage' I have hit.
If you're pulling out the students from a database (mentioned in the comments), you could retrieve them with the desired format directly using SQL.
However, I'm going to assume that that's not an option. You could do as follows:
$students = array(1201=>94,1203=>94,1200=>91, 1205=>89, 1209=>83, 1206=>65, 1202=>41, 1207=>38,1208=>37, 1204=>37,1210=>94);
arsort($students);// It orders high to low by value. You could avoid this with a simple ORDER BY clause in SQL.
$result = array();
$pos = $real_pos = 0;
$prev_score = -1;
foreach ($students as $exam_n => $score) {
$real_pos += 1;// Natural position.
$pos = ($prev_score != $score) ? $real_pos : $pos;// If I have same score, I have same position in ranking, otherwise, natural position.
$result[$exam_n] = array(
"score" => $score,
"position" => $pos,
"exam_no" => $exam_n
);
$prev_score = $score;// update last score.
}
$desired = 1207;
print_r($result);
echo "Student " . $result[$desired]["exam_no"] . ", position: " . $result[$desired]["position"] . " and score: ". $result[$desired]["score"];
Hope it helps you.
I would use a custom object to process the students individually and store them in an array.
$students = array(1201=>94,1203=>94,1200=>91, 1205=>89, 1209=>83, 1206=>65, 1202=>41, 1207=>38,1208=>37, 1204=>37,1210=>94);
arsort($students); // Sort the array so the higher scores are on top.
$newStudents = array();
$pos = 0;
$count = 0;
$holder = -1; // Assuming no negative scores.
foreach($students as $k=>$v){
$count++; // increment real counter
if($v < $holder || $holder == -1){
$holder = $v;
$pos = $count;
}
$newStudents[] = makeStudent($pos, $v, $k);
// If you want the exam # as the array key.
// $newStudents[$k] = $student;
}
$newStudents = fixLast($newStudents);
// outputs
print_r($newStudents);
foreach($newStudents as $v){
echo "position : " . $v->position . "<br>";
echo "score : " . $v->score . "<br>";
echo "exam : " . $v->exam . "<br>";
}
function makeStudent($pos, $score,$examNo){
$student = new stdClass(); // You could make a custom, but keeping it simple
$student->position = $pos;
$student->score = $score;
$student->exam = $examNo;
return $student;
}
function fixLast($students){
$length = count($students) -1;
$count = 0;
$i = $length;
while($students[$i]->position == $students[--$i]->position){
$count++;
}
for($i = 0; $i <= $count; $i++){
$students[$length - $i]->position = $students[$length - $i]->position + $count;
}
return $students;
}
I've got a problem which takes up a lot of time. While it's supposed to be really easy (because it's just so simple!).
My problem:
I have these values inside two arraylists:
$row[0]->COUNTER1 20 10 15
$row[0]->GRADE_POINTS 0 3 5
I am supposed to change these arraylists into this example:
$row[0]->COUNTER1 20 0 0 10 0 15
$row[0]->GRADE_POINTS 0 1 2 3 4 5
So the missing values are supposed to have 0 as the counter.
While this isn't that hard to do it I'm probably over thinking it.
The code which I use to create the first set of numbers is:
$result = new SimpleXMLElement($xmlresult);
$xml = $result->children("soapenv", true)->Body->children();
$xmlBody = $xml[0];
$countPerResultaat = array();
foreach($xmlBody->query[0] as $row)
{
$countPerResultaat[] = (int) $row[0]->COUNTER1;
$xaxis[] = (string) $row[0]->GRADE_POINTS;
}
The code I though that would work is this:
for($i; $i<=10; $i++){
//foreach($xmlBody->query[0] as $row)
//{
$row = $xmlBody->query[0];
if($i==$row[0]->GRADE_POINTS){
$countPerResultaat[] = (int) $row[0]->COUNTER1;
$xaxis[] = (string) $row[0]->GRADE_POINTS;
}else{
$xaxis[] = (string) $i;
$countPerResultaat[] = (int) 0;
}
}
But the row can't be used, I really don't know how to fix this. My only solution would be to use another for-loop, which would create 100 values probably.
Thanks for helping in advance!
If I understand correctly and if $row[0]->COUNTER1 and $row[0]->GRADE_POINTS are arrays. You will just need to loop them and use in_array(). Consider this example:
$counter1 = array(20, 10, 15);
$grade_points = array(0, 3, 5);
$new_grade_points = range(min($grade_points), max($grade_points));
foreach($new_grade_points as $key => &$value) {
// check if its part of the missing index if not get the value,
// if its the missing index put 0
$value = (in_array($key, $grade_points)) ? array_shift($counter1) : 0;
}
$counter1 = array_values($new_grade_points); // now contains 20,0,0,10,0,15
$grade_points = array_keys($new_grade_points); // now contains 0,1,2,3,4,5
print_r($counter1);
Sample Output:
Array
(
[0] => 20
[1] => 0
[2] => 0
[3] => 10
[4] => 0
[5] => 15
)
I think you want to count the amount of times a grade has been given? You should just loop through as usual, and when there is no value you should/could define it as 0. After that just count how many duplicates you have in the array. That way the key of the $xaxis is the grade, and the value is the amount of times that grade has been given.
foreach($xmlBody->query[0] as $row)
{
$counter = (int) $row[0]->COUNTER1;
if(counter) $countPerResultaat[] = $counter;
else $countPerResultaat[] = 0;
}
$xaxis = array_count_values($counter);
I have the following array:
$learners=array('Eliza'=87, 'Joe'=81, 'Anne'=69, 'Marley'=39, 'Teddy'=39, 'Jemma'=90, 'Sylvia'=87);
So far I have been able to separate the two arrays as follows:
$tudents=array_keys($learners);
$scores=array_values($learners);
The ranking is as follows:
Student Score Position
Jemma 90 1
Sylvia 87 2
Eliza 87 2
Joe 81 4
Anne 69 5
Marley 39 7
Teddy 69 7
I would like to create a new array with names as keys and positions as values i.e
$positions=array('Jemma'=1, 'Sylvia'=2, 'Eliza'=2, 'Joe'=4, 'Anne'=5, 'Marley'=7, 'Teddy'=7);
This will allow me to echo any name and position at any point on the script. I am not sure how to proceed.
The ranking is not straightforward if the scores have duplicates. If there is a tie at number 2, the 3rd position is skipped. If the tie occurs at the end of the scores, then both scores will be placed at the last position and the preceding position will be skipped, in the example above, position 6 has been skipped and the two 39s occupy position 7.
Any help will be appreciated
// Sort decending
arsort($data);
$vals = array_values($data);
$last = end($vals); // The lowest score
$prev = null;
$rank = 0;
$positions = array();
foreach($data as $student => $score) {
if ($score == $last) {
// The score is the same as the lowest, the rank is set to last position
$rank = count($data);
} else if ($prev != $score) {
// We only update if the score is not the same as prev
$rank++;
} else if ($prev == $score) {
// We matched on the key, replace any items with the
// same score with the current rank
$matches = array_keys($positions, $score);
foreach($matches as $key) {
$positions[$key] = $rank;
}
$positions[$student] = $rank;
// Now skip ahead to the next rank +1
$rank = $rank + count($matches) + 1;
continue;
}
$positions[$student] = $rank;
$prev = $score; // Remember the previous score
}
var_dump($positions);
Here's another solution:
First sort by value (the print_r is just to check progress).
arsort($learners);
print_r($learners);
Then make an array of rankings, but don't advance the rank if the score is the same as the previous element's score.
$rank = $pos = 1;
$prev_score = current($learners);
foreach ($learners as $name => $score) {
if ($score != $prev_score) {
$rank = $pos;
}
$ranking[$name] = $rank;
$prev_score = $score;
$pos++;
}
print_r($ranking);
Now correct the last entries, any element with the same score as the last element should be in 7th place. There's a rarely-used argument to array_keys() that searches for a given value.
$low_score = end($learners);
$last_place = count($learners);
foreach (array_keys($learners, $low_score) as $name) {
$ranking[$name] = $last_place;
}
print_r($ranking);
Output:
Array
(
[Jemma] => 90
[Sylvia] => 87
[Eliza] => 87
[Joe] => 81
[Anne] => 69
[Marley] => 39
[Teddy] => 39
)
Array
(
[Jemma] => 1
[Sylvia] => 2
[Eliza] => 2
[Joe] => 4
[Anne] => 5
[Marley] => 6
[Teddy] => 6
)
Array
(
[Jemma] => 1
[Sylvia] => 2
[Eliza] => 2
[Joe] => 4
[Anne] => 5
[Marley] => 7
[Teddy] => 7
)
Looks like PHP, right?
Basically go through your initial list and stuff them into a new array that uses the names as keys (you're in trouble here if two people have the same name, but I'm assuming this is a homework assignment and that's not an issue?)
$sorted = array();
for ($i=0;$i<count($positions);$i++) {
if (!isset($sorted[$positions[$i]["Student"]])) {
$sorted[$positions[$i]["Student"]] = $positions[$i]["Score"];
} else if ($sorted[$positions[$i]["Student"]]<$positions[$i]["Score"] {
$sorted[$positions[$i]["Student"]] = $positions[$i]["Score"];
}
}
What you're doing here is making an array where the KEY is the name of the student, and putting the first score you find in as the VALUE for that. So $sorted["Jemma"] = 90. Then if you hit that name again, and the score is higher than the current value for $sorted["Jemma"], you're replacing it.
After that, you run an arsort($sorted) to put it in order.
Program:
while($i<=$row) {
echo $arr[$i][1].$arr[$i][4]
}
Output
Product Code Qty
KC_DRINK_TASTY_CASE 1
KC_DRINK_TASTY_CASE 1
KC_DRINK_TASTY_CASE 1
KC_DRINK_TASTY_CASE 1
KC_SUNGLASSES_BK 1
KC_SUNGLASSES_BK 1
KC_SUNGLASSES_BE 1
KC_SUNGLASSES_BE 1
KC_SUNGLASSES_OE 1
KC_SUNGLASSES_OE 1
KC_SUNGLASSES_RD 1
KC_SUNGLASSES_RD 1
KC_SUNGLASSES_WE 1
KC_SUNGLASSES_WE 1
I want it to output
KC_DRINK_TASTY_CASE 4
KC_SUNGLASSES 10
so that it group product code excluding last underscore and sum their quantity
If $arr looks something like this:
$arr = array(
array('{something}', 'KC_DRINK_TASTY_CASE', '{something}', '{something}', 1),
array('{something}', 'KC_SUNGLASSES_BK', '{something}', '{something}', 1),
// ...
);
Then you can get the output what you what like this:
// we'll store counts here
$result = array();
foreach ($arr as $row) {
$product = $row[1];
$qty = $row[4];
// figure out where the last underscore is and chop off everything that follows it
// this is VERY brittle. If the product ends up with a name like _SOMEKEY you'll end
// up with an empty key. Not good. Probably not a huge issue, but buyer beware
$_product = substr($product, 0, strrpos($product, '_'));
if (isset($result[$_product])) {
$result[$_product] += $qty; // we already started counting
} else {
$result[$_product] = $qty; // not started counting this product yet, start it
}
}
// now print your result:
foreach ($result as $id => $qty) {
echo $id, "\t", $qty, PHP_EOL;
}