PHP foreach loop to build multi array - php

I'm trying to build a multi array with this structure:
Array
(
[2] => Array //this is the user's unique ID
(
[name] => Jack
[location] => Somerville, Massachusetts, United States
[cars] => Array
(
[10] => Toyota //this is the car's unique ID
[11] => Porsche
)
)
[5] => Array
(
[name] => Luke
[location] => Schwelm, North Rhine-Westphalia, Germany
[cars] => Array
(
[1] => Honda
[2] => VW
[5] => Maserati
)
)
[1] => Array
(
[name] => Jabba
[location] => Denver, Colorado, United States
[cars] => Array
(
[3] => Tesla
)
)
)
I am using this foreach loop but am stuck in getting the cars array embedded within the search data array.
Each user may have more than one car so I would need to loop through all cars for each user, generate that array, and put it in the original foreach loop.
$search_data = array();
foreach ($query->result() as $row) {
$search_data[$row->id] = array(
'name' => $row->name,
'location' => $row->location,
'cars' => array($row->car_id), //this is where I need to insert another array
);
}
return $search_data;
Any suggestions how to do this?
Thanks for helping!
SAMPLE TABLE DATA
USER NAME LOCATION CARS
2 JACK A TOYOTA
2 JACK A PORSCHE
5 LUKE B HONDA
5 LUKE B VW
5 LUKE B MASERATI
1 JABBA C TESLA

It seems that you are creating the array through a database table. So can you please give 2 or more sample data. it'll be easier to give an answer if sample data is there.
Edit:
Well this might not be the best code but I think you'll be able to figure out a better way after seeing this
$id = $row['id'];
if (!isset($search_data[$id])){
$search_data[$id] = array();
}
$search_data[$id]['name'] = $row['name'];
$search_data[$id]['location'] = $row['location'];
if (isset($search_data[$id]['cars'])) {
array_push($search_data[$id]['cars'],$row['cars']);
}else{
$search_data[$id]['cars'] = array($row['cars']); //this is where I need to insert another array
}

Related

Alphabetizing multidimensional array with SQL or PHP

I'm working on programming a gradebook, and I've ran into a bit of an issue I'm trying to figure out how to approach.
I have three tables which are at play in this script: (1) the "assignments" table which contains info about each assignment, (2) the "assignGrades" table which contains student scores on assignments (3) the "students" table which contains student information.
Now, the problem is coming whenever I add a new student to the class. Logically, if a student joins a class mid-semester, they would not be assigned "past work" from earlier in the year. With this in mind, there would be no "connection" for an INNER JOIN statement. I have already tried using "LEFT JOIN" and "RIGHT JOIN" in this instance, but I am not having any luck.
Whenever I go to build a PHP array with the SQL statement below, I am running into a problem. If a student was added mid year, they are not properly alphabetizing into the array, which comes from the SELECT statement and the way this is organized. See the example below for student "Amy Appleton" which was added mid year, and is not in proper alphabetical order.
HOW I NEED HELP / DESIRED END RESULT:
I am trying to determine how to alphabetize my $array to be organized in order of last name. I have determined I will either accomplish this through rewriting my SQL statement or through using some sort of PHP usort, although I would much rather organize data on the SQL side if possible. My best guess would be to accomplish this through a LEFT JOIN, but I have tried every variation possible within my SQL statement and have not gotten any desired results.
SQL statement used:
SELECT students.firstName, students.lastName, assignments.assID, assignments.assEmoji, assignments.points, assignments.title, assignments.assigned, assignments.due, assignGrades.*
FROM students
LEFT JOIN assignGrades ON students.usid = assignGrades.usid
LEFT JOIN assignments ON assignGrades.assID = assignments.assID
WHERE subID=? OR subID IS NULL ORDER BY due, lastName, firstName
Snipet from PHP that is building the $array
while ($row = mysqli_fetch_assoc($results)) {
$array['assignments'][$row['assID']]['assEmoji'] = $row['assEmoji'];
$array['assignments'][$row['assID']]['title'] = $row['title'];
$array['assignments'][$row['assID']]['points'] = $row['points'];
$array['assignments'][$row['assID']]['assigned'] = $row['assigned'];
$array['assignments'][$row['assID']]['due'] = $row['due'];
$array['students'][$row['usid']]['firstName'] = $row['firstName'];
$array['students'][$row['usid']]['lastName'] = $row['lastName'];
$array['students'][$row['usid']]['fullName'] = $row['firstName']." ". $row['lastName'];
if ($row['status'] == 'graded' || $row['status'] == 'missing') {
$array['students'][$row['usid']]['earned'] = $array['students'][$row['usid']]['earned'] + $row['score'];
$array['students'][$row['usid']]['maxpts'] = $array['students'][$row['usid']]['maxpts'] + $row['points'];
}
$array['students'][$row['usid']]['submissions'][$row['assID']]['workID'] = $row['workID'];
$array['students'][$row['usid']]['submissions'][$row['assID']]['status'] = $row['status'];
if (isset($row['submitted'])) {$array['students'][$row['usid']]['submissions'][$row['assID']]['submitted'] = $row['submitted'];}
if (isset($row['method'])) {$array['students'][$row['usid']]['submissions'][$row['assID']]['method'] = $row['method'];}
if (isset($row['score'])) {$array['students'][$row['usid']]['submissions'][$row['assID']]['score'] = $row['score'];}
if (isset($row['score'])) {$array['students'][$row['usid']]['submissions'][$row['assID']]['points'] = $row['points'];}
if (isset($row['graded'])) {$array['students'][$row['usid']]['submissions'][$row['assID']]['graded'] = $row['graded'];}
if (isset($row['method'])) {$array['students'][$row['usid']]['submissions'][$row['assID']]['method'] = $row['method'];}
}
return $array;
Example print_r($array) from the SQL statement (Amy Appleton should appear on the top of $array['students'] since she is alphabetically before the other two students. However, since there is no entry on the assignGrades table for assignment #9 for her, she appears at the bottom)
Array
(
[assignments] => Array
(
[9] => Array
(
[assEmoji] => ✏️
[title] => Beginning of Year Activities
[points] => 10
[assigned] => 2021-08-16
[due] => 2021-08-20 15:00:00
)
[10] => Array
(
[assEmoji] => ✏️
[title] => Mid Year Project
[points] => 10
[assigned] => 2021-09-23
[due] => 2021-09-30 15:00:00
)
)
[students] => Array
(
[11] => Array
(
[firstName] => Zeke
[lastName] => Lee
[fullName] => Zeke Lee
[earned] => 103
[maxpts] => 120
[submissions] => Array
(
[9] => Array
(
[workID] => 539
[status] => graded
[submitted] => 2021-08-17 08:15:48
[method] => wall
[score] => 9
[points] => 10
[graded] => 2021-09-22 10:26:54
)
[10] => Array
(
[workID] => 541
[status] => graded
[submitted] => 2021-09-23 08:15:48
[method] => wall
[score] => 9
[points] => 10
[graded] => 2021-09-23 10:26:54
)
)
)
[12] => Array
(
[firstName] => John
[lastName] => Smith
[fullName] => John Smith
[earned] => 91
[maxpts] => 110
[submissions] => Array
(
[9] => Array
(
[workID] => 540
[status] => graded
[submitted] => 2021-08-17 08:45:48
[method] => wall
[score] => 7
[points] => 10
[graded] => 2021-09-22 10:28:54
)
[10] => Array
(
[workID] => 590
[status] => graded
[submitted] => 2021-09-23 09:15:48
[method] => wall
[score] => 9
[points] => 10
[graded] => 2021-09-23 11:24:54
)
)
)
[13] => Array
(
[firstName] => Amy
[lastName] => Appleton
[fullName] => Amy Appleton
[earned] => 91
[maxpts] => 110
[submissions] => Array
(
[10] => Array
(
[workID] => 913
[status] => graded
[submitted] => 2021-09-23 10:45:48
[method] => wall
[score] => 7
[points] => 10
[graded] => 2021-09-23 12:31:54
)
)
)
)
)
Array structure:
$array['assignments'][assID][details]
$array['students'][usid][details]
$array['students'][usid]['submissions'][assID][details]
Screenshots of table structure from SQL
Screenshot of CSV dump from SQL query
The main issue I see is that your query is trying to do too much. It is trying to get assignments in a specific order (by due), as well as students and their submissions in a different order (by lastName, firstName). For this reason, I would break this up into 2 separate queries. You can combine the datasets later to make your final data structure.
retrieve the assignments and order them by due date. This is a very simple query and the result set can be used directly.
retrieve all students and their submissions, if they exist, and order them by lastName, first name. Then, in PHP, manipulate the dataset into the format you need.
Pseudocode
// Get assignments. These can be used directly in your data structure `$combined`.
//
// Order by due date
$assignments = SELECT ... FROM assignments
WHERE ...
ORDER BY due;
// Get students and their assignments. These need to be manipulated to fit your
// requirements. Use a left join here because a student may not have started
// an assignment yet.
//
// Order by lastName, firstName
$students = SELECT ... FROM students a
LEFT JOIN assignGrades b ON b.usid = a.usid
ORDER BY lastName, firstName;
// See http://sandbox.onlinephpfunctions.com/code/9460c51954f8ea00f7ba75adadfcbf91fc03076e
// Loop over the student/submission dataset and manipulate it.
$studentMapping = [];
foreach($students as $row) {
// Build up student data if it doesn't already exist.
// Importantly, create an empty submissions element. If the student's
// submission doesn't exist, this is what will be returned.
$student = $studentMapping[$row['usid']] ?? [];
if (empty($student)) {
$student = [
'firstName' => $row['lastName'],
'lastName' => $row['lastName'],
...
'submissions' => [],
];
}
// Build up submissions data for the student if they have submitted an assignment.
// If they haven't submitted an assignment yet, their submissions array will remain empty.
if (!empty($row['assignment_id'])) {
$student['submissions'][] = [
'assignmentId' => $row['assignment_id'],
'status' => $row['status'],
...
];
}
// Finally, assign the student (and their submissions) to the $studentMapping array.
$studentMapping[$row['usid']] = $student;
}
// Now combine them into your final datastructure.
$combined = [
'assignments' => $assignments,
'students' => $studentMapping,
];

PHP - if array data meets criteria then change before page is loaded

Variable $list stores an array like the one below.
Array
(
[0] => Array
(
[warehouse] => Array
(
[warehouseName] => Warehouse Europe
[warehouseType] => en detail
)
[products] => Array
(
[0] => Array
(
[productName] => APPAREL SHIRTS
[productCode] => 54059761696
[measuringUnit] => buc
[quantity] => 1
)
[1] => Array
(
[productName] => T-SHIRTS - SADAL
[productCode] => 54059764755
[measuringUnit] => buc
[quantity] => 0
)
........... more data ............
Using the following piece of code I print it on the display:
foreach($list as $item) {
foreach($item['products'] as $product) {
$wName = $item['warehouse']['warehouseName'];
$wType = $item['warehouse']['warehouseType'];
$pr =implode(',',$product);
printf("%s,%s,%s".PHP_EOL,$wName,$wType,$pr);
}
}
How can i search if quantity is more than 3, and if it meets the criteria than change it to ">2" before the information is passed to the browser?
Basically i need to keep the quantity confidential and only show ">2" if 3 or more products are retrieved from the array.
Thanks!
You can check whether the quantity is more than 2 and change the value you're going to display by using a ternary operator. So inside your inner foreach, before printing, you can do
$quantity = ($product['quantity'] > 2 ? '>2' : $product['quantity']);
Then you can print $quantity wherever you want it (as long as you're still inside your inner loop).

Arrange array and delete duplicate values

I'm stuck with a tricky task I can't solve without the code being very messy with a lot of foreach loops.
This is the fundamental logic:
There can only be unique foods in the array, so only one guy can have Pizza, only one guy can have Pasta etc. But they can have multiple foods. And the guy with the most foods in the array, should win the foods over the ones with few foods.
So John should be deleted from the array since either Joe or Conny will have his.
And since Joe and Conny have the same amount of foods, one of them will keep all of his foods and the other one should be deleted from the array and it should be picked randomly whether it is Joe or Conny.
The starting array looks like this:
Array
(
[Joe] => Array
(
[0] => Pizza
[1] => Pasta
[2] => Lasagne
[3] => Tacos
[4] => Hamburger
)
[Conny] => Array
(
[0] => Pizza
[1] => Pasta
[2] => Lasagne
[3] => Tacos
[4] => Hamburger
)
[John] => Array
(
[0] => Pizza
[1] => Pasta
)
[Fred] => Array
(
[0] => Pizza
[1] => Pasta
[2] => Soup
[3] => Fish
)
[Greg] => Array
(
[0] => Sushi
)
)
And the end result I want is:
Array
(
[Joe] => Array
(
[0] => Pizza
[1] => Pasta
[2] => Lasagne
[3] => Tacos
[4] => Hamburger
)
[Fred] => Array
(
[2] => Soup
[3] => Fish
)
[Greg] => Array
(
[0] => Sushi
)
)
So only unique foods left in the array and if two or more guys have the same amount, it should randomly pick whether of these should keep the foods.
Any suggestions how I can do this?
You have to first sort the array depending on the count of elements in the subarray in reverse order using an user-defined function with uasort. Then you can use two foreach loops to loop through the loop. You will use a helper variable to determine if a food has already been used and if so unset the element. After doing that you filter out the empty elements in the array with array_filter.
uasort($food, function($a, $b) {
return count($b) <=> count($a);
});
$used = array();
foreach($food as $kl => $pl) {
foreach($pl as $k => $p) {
if(!in_array($p, $used)) {
$used[] = $p;
} else {
unset($food[$kl][$k]);
}
}
}
$food = array_filter($food);
You can see it here: https://3v4l.org/LjpGD
Reference:
http://php.net/uasort
http://php.net/in_array
http://php.net/array_filter
PS: The code uses the new since PHP 7.0 available spaceship operator. If you don't or can't use PHP7, you have to use an if construct as below for comparison.
if(count($b) > count($a)) {
return 1;
} elseif(count($b) == count($a)) {
return 0;
} else {
return -1;
}

How to merge sub-arrays based on first value php

I have an array that is put together. It's basically 24 data points across 7 stations. Each station has a data point each hour and a new sub0array is created for each data point. The problem with this, is I now want to split the data up based on station so I can sort it. When I go to do that array_filter doesn't work for me. I wanted to basically combine all of the values that have the same row 0 result in each sub-array. but keep each data point based on them. Row 0 is the station name. Here is an example of what the array looks like. There are 160 sub arrays. All I need to do is combine them together based on Station name. I was going to do this based on Array value, but the problem is if a data-point is missing, it breaks that logic.
Array
(
[0] => Array
(
[0] => STATIONONE
[1] => 02/22/15 04:00:00 PM
[2] => SW
[3] => Array
(
[0] => 4.51
)
[4] => MPH
[5] => Array
(
[0] => 16.1
)
[6] => MPH
)
[1] => Array
(
[0] => STATIONONE
[1] => 02/22/15 05:00:00 PM
[2] => S
[3] => Array
(
[0] => 2.7
)
[4] => MPH
[5] => Array
(
[0] => 9.61
)
[6] => MPH
)
And it just keeps repeating till I have 23 Values. Then the next station.
So 0-22 subarray value = station 1
23-45 subarray value = station 2
etc.. just stating to help show what I am trying to do.
It isn't entirely clear what you expect your output to be, but this might get you there:
$entriesByStation = []
foreach ($entries as $entry) {
$entriesByStation[$entry[0]] = $entry;
}
This will group all the the entries by station name in the $entriesByStation array
The accepted answer got me close into figuring this out. I had to do this by station though. So I just created 7 foreach statements and created an array for each station. This way I can also merge the array together if needed.
# Parse our All Data and set station
foreach ($array as $entry) {
if ($entry[0] === "STATIONONE"){
$S1pkwsite = ($entry[0]);
$S1pkwvalue = ($entry[5][0]);
$S1pkwdate = ($entry[1]);
$S1pkwunit = ($entry[6]);
$S1wspvalue = ($entry[3][0]);
$S1wspunit = ($entry[4]);
$S1wdrvalue = ($entry[2]);
$S1pkwdataarray[] = array('SiteName'=>$S1pkwsite,'DATE'=>$S1pkwdate,'WDR'=>$S1wdrvalue,'VALUE'=>$S1pkwvalue,'UNIT'=>$S1pkwunit);
}
}
array_push ($Stationone_data, $pkwdataarray);
$Stationone_data = array_shift($Stationone_data);

php array sorting and grouping

I have an array of Towns that have no sorting whatsoever. I would like to sort by the [category][3] which is the province and then the [category][0] which is the region and display each Grouped Province with its regions and then towns underneath it. So the following array:
Array
(
[0] => Array
(
[name] => Name One
[id] => 1
[link] => http://mylink1.com
[category] => Array
(
[0] => Region 1
[1] => Town 7
[2] => Country
[3] => Province 2
)
)
[1] => Array
(
[name] => Name Two
[id] => 2
[link] => http://mylink2.com
[category] => Array
(
[0] => Region 1
[1] => Town
[2] => Country
[3] => Province 3
)
)
[2] => Array
(
[[name] => Name Three
[id] => 3
[link] => http://mylink3.com
[category] => Array
(
[0] => Region 1
[1] => Town 5
[2] => Country
[3] => Province 2
)
)
[6] => Array
(
[name] => Name Four
[id] => 4
[link] => http://mylink4.com
[category] => Array
(
[0] => Region 1
[1] => Town 1
[2] => Country
[3] => Province 1
)
)
)
... should end up looking like this:
Country (all the same)
Province 1
- Region 1
- - Town 1 name, id, link
Province 2
- Region 1
- - Town 5 name, id, link
- - Town 7 name, id, link
Province 3
- Region 1
- - Town 1 name, id, link
Province is the Primary Grouping factor, then sorted by Region, the Towns in no particular order but I guess Alphabetically would make sense.
I have managed to sort the array by Category using this reference: Sort Multi-dimensional Array by Value but cannot fathom how to sort any further without referencing the Province specifically in a loop by using its name. i.e.
/// shortened version..
foreach($array as $key=>$value)...
if($value == "Province 1") : do something here with these matches
... etc
Any help would be appreciated.
Take a look at the uasort() function:
http://www.php.net/manual/en/function.uasort.php
I don't think that you can do this in one step.
You can group your values like this:
$grouped = array();
foreach ($data as $group)
{
$grouped[ $group['category'][3] ][ $group['category'][0] ][ $group['category'][1] ] = array(/* ... */);
}
But you will still have to sort every array (and it's sub-arrays) using ksort().
You should check, whether you can get the values already presorted. If you, for example, are using a database to retrieve this values, it would be quite trivial to sort them in the database and bring them in the correct (grouped) structure in your PHP code.
looping through the array I've used a switch for the category I'm looking for and then built another array for each group. from there I can sort by region:
foreach($arr as $town){
switch($town['blogcats']){
case "Province 1" : $province1[] = $town;
break;
case...
etc
}
}
Then each new grouped array can be output:
foreach($province1 as $eachtown) {
echo $newtown['name'];
... and so forth.
}
Within the second loop sorting could be done on the Region.
Each Province is manually referenced in a list on my page which also gives me control over placement.
Howver, this answer could also be improved... but the above works without too much effort.

Categories