Sort array in groups and people with foreach - php

I am trying to sort an array into groups and people.
the problem is that it only shows me one person per class when I use the counter "pos_group = 0" but if I put it in negative and increase it in the "IF" if I get the result.
Am I doing something else in the assignment of the new array?
<?php
$data = [
0 => [
'g_id' => 22,
'g_name' => 'ABC',
'u_id' => 1,
'u_name'=> 'Pepe'
],
1 => [
'g_id' => 22,
'g_name' => 'ABC',
'u_id' => 2,
'u_name'=> 'Mario'
],
2 => [
'g_id' => 22,
'g_name' => 'ABC',
'u_id' => null,
'u_name'=> null
],
3 => [
'g_id' => 31,
'g_name' => 'CDE',
'u_id' => 3,
'u_name'=> 'Juan'
],
4 => [
'g_id' => 41,
'g_name' => 'EFG',
'u_id' => 4,
'u_name'=> 'Pedro'
],
];
$last_group_id = null;
$pos_group = 0;
foreach ($data as $group_user):
//Add Groups
if($last_group_id != $group_user['g_id']){
//$pos_group ++;
$final[$pos_group] = [
'g_id' => $group_user['g_id'],
'g_name' => $group_user['g_name']
];
//$last_group_id = $group_user['g_id'];
//$pos_group ++;
}
//Add Members
if(!is_null($group_user['u_id'])){
$final[$pos_group]['members'][$group_user['u_id']] = [
'u_id' => $group_user['u_id'],
'u_name' => $group_user['u_name']
];
}
if($last_group_id != $group_user['g_id']){
$pos_group ++;
$last_group_id = $group_user['g_id'];
}
endforeach;
echo "<pre>";
print_r($final);
//var_dump($final);
echo "</pre>";
?>
expected:
Array
(
[0] => Array
(
[g_id] => 22
[g_name] => ABC
[members] => Array
(
[1] => Array
(
[u_id] => 1
[u_name] => Pepe
)
[2] => Array
(
[u_id] => 2
[u_name] => Mario
)
)
)
[1] => Array
(
[g_id] => 31
[g_name] => CDE
[members] => Array
(
[3] => Array
(
[u_id] => 3
[u_name] => Juan
)
)
)
[2] => Array
(
[g_id] => 41
[g_name] => EFG
[members] => Array
(
[4] => Array
(
[u_id] => 4
[u_name] => Pedro
)
)
)
)
I only get that result by setting the variable to -1 and increasing the counter after the "if", like this:
$last_group_id = null;
$pos_group = -1;
foreach ($data as $group_user):
//Add Groups
if($last_group_id != $group_user['g_id']){
$pos_group ++;
$final[$pos_group] = [
'g_id' => $group_user['g_id'],
'g_name' => $group_user['g_name']
];
$last_group_id = $group_user['g_id'];
//$pos_group ++;
}
//Add Members
if(!is_null($group_user['u_id'])){
$final[$pos_group]['members'][$group_user['u_id']] = [
'u_id' => $group_user['u_id'],
'u_name' => $group_user['u_name']
];
}
// if($last_group_id != $group_user['g_id']){
// $pos_group ++;
// $last_group_id = $group_user['g_id'];
// }
endforeach;
It's a bit silly but I can't find the problem XD
thanks !

It has to do with the position of your counter increment. The first case increments at the end of the loop, while the second one does it early in the loop. Let's observe what happens in the first case (incrementing at the end):
first iteration
$pos_group is 0
a new group is added (with id 22) at index 0
a new member is added inside that group (Pepe)
$pos_group is incremented to 1
second iteration
$pos_group is 1
group is not added as it is the same as the previous one
a new member is added (Mario), but at index 1, which places it outside the group (because the first member was added while $pos_group was 0)
$pos_group is not incremented
third iteration
here no changes are made, group is the same and id is null
fourth iteration
$pos_group is still 1 (no increment in last two iterations)
a new group is added at index 1, overwriting poor Mario
...algorithm continues normally until the end...
So the discrepancy happens because the first two members of the group are added at different indices. Incrementing the $pos_group variable at the beginning, before any additions, removes the problem, thus giving correct result.
But I'd like to suggest a simplified algorithm for this purpose:
$final = [];
foreach ($data as $groupUser) {
if (null !== $groupUser['u_id']) {
/* Note that for the final array I use the group id as key. That way
instead of tracking the current position and last group, you can simply
add at the group id index. I am also overwriting the group info every time
instead of checking if it exists (for simplicity), becuase there is no harm
done since it will always be the same. */
$final[$groupUser['g_id']]['g_id'] = $groupUser['g_id'];
$final[$groupUser['g_id']]['g_name'] = $groupUser['g_name'];
// add member, we've already checked the id against null
$final[$groupUser['g_id']]['members'][$groupUser['u_id']] = [
'u_id' => $groupUser['u_id'],
'u_name' => $groupUser['u_name']
];
}
}
No multiple checks, no additional variables to track, with the added benefit of working on unsorted data as well. The only difference is that my solution will have top level keys equal to group ids:
Array
(
[22] => Array...
[31] => Array...
If this is in any way a problem for you, all you have to do is grab array_values($final) to get a reindexed array, starting at 0.

Related

Sum parts of an array in php

this is quite beyond me. Appreciate some help.
I have an array in php like so:
[0] => Array
(
[cust_id] => 1006
[no_of_subs] => 2
[dlv_id] => 1000
)
[1] => Array
(
[cust_id] => 1011
[no_of_subs] => 3
[dlv_id] => 1000
)
[2] => Array
(
[cust_id] => 1012
[no_of_subs] => 5
[dlv_id] => 1001
)
[3] => Array
(
[cust_id] => 1013
[no_of_subs] => 6
[dlv_id] => 1001
)
I don't need the cust_id field. I just need to group the dlv_id and the sum of no_of_subs for each matching dlv_id. The result should look like this:
[0] => Array
(
[dlv_id] => 1000
[no_of_subs] => 5
)
[1] => Array
(
[cust_id] => 1011
[no_of_subs] => 11
)
Thank you for any help.
I don't understand the downvotes for this question. Am i doing it all wrong? Downvoting without a reason is not helping.
The simplest, most efficient way to group and sum is to perform a single loop and assign temporary associative keys.
When a row is identified as a new dlv_id row, save the two desired elements, otherwise add the no_of_subs value to the pre-existing value.
Optionally, remove the temporary keys with array_values().
Code (Demo)
$array = [
["cust_id" => 1006, "no_of_subs" => 2, "dlv_id" => 1000],
["cust_id" => 1011, "no_of_subs" => 3, "dlv_id" => 1000],
["cust_id" => 1012, "no_of_subs" => 5, "dlv_id" => 1001],
["cust_id" => 1013, "no_of_subs" => 6, "dlv_id" => 1001]
];
foreach ($array as $row) {
if (!isset($result[$row["dlv_id"]])) {
$result[$row["dlv_id"]] = ["dlv_id" => $row["dlv_id"], "no_of_subs" => $row["no_of_subs"]];
} else {
$result[$row["dlv_id"]]["no_of_subs"] += $row["no_of_subs"];
}
}
var_export(array_values($result));
Output:
array (
0 =>
array (
'dlv_id' => 1000,
'no_of_subs' => 5,
),
1 =>
array (
'dlv_id' => 1001,
'no_of_subs' => 11,
),
)
Using array_column function, we can extract out dlv_id and no_of_subs separately in two different arrays, using cust_id as the key.
Now, simply loop over the array of dlv_id, and if matching key found, add the no_of_subs to it, else set the value (for the first time).
We use isset function to check if the key exists already or not.
Try the following:
// your input array is $input_array
// get all dlv_id maintaining the cust_id as index
$dlv_id = array_column($input_array, 'dlv_id', 'cust_id');
// get all no_of_subs maintaining the cust_id as index
$no_of_subs = array_column($input_array, 'no_of_subs', 'cust_id');
$output = array();
foreach ($dlv_id as $key => $value) {
if (isset($output[$value]['dlv_id'])) {
$output[$value]['dlv_id'] += $no_of_subs[$key];
} else {
$output[$value]['dlv_id'] += $no_of_subs[$key];
}
}

require value and respective key from array in php

I have a a array like below and i want min value and it's index for searching tax class id
Array
(
[tax_class_id] => Array
(
[0] => 12
[1] => 13
[2] => 13
)
[price] => Array
(
[0] => 6233
[1] => 3195
[2] => 19192
)
)
and i am searching least price and respective key in tax_class_id. In this Senario, i require lowest in price i.e 3195 and tax_id - 13 i.e key [1]
My Code is
$prod_total = array();
for($i = 1;$i <= $chunk;$i++){
if($i == 1) {
$min_product_amt = min($product_amt['price']);
$index = array_search($min_product_amt, $product_amt);
$product_total = $min_product_amt;
//ceil Round numbers up to the nearest integer
$prod_total['price'] = ceil($product_total * $discount/100);
$prod_total['tax_id'] = $product_amt['tax_class_id'];
//Remove the first element from an array
array_shift($product_amt['price']);
array_shift($product_amt['tax_class_id']);
} else {
$second_min_product_amt = min($product_amt['price']);
$index = array_search($min_product_amt, $product_amt);
$product_total = $second_min_product_amt;
$prod_total['price'] = ceil($product_total * $discount/100);
$prod_total['tax_id'] = $product_amt['tax_class_id'];
array_shift($product_amt['price']);
array_shift($product_amt['tax_class_id']);
}
}
print_r($prod_total);
die;
$array=Array
(
'tax_class_id' => Array
(
0 => 12,
1 => 13,
2 => 13
),
'price' => Array
(
0 => 6233,
1 => 3195,
2 => 19192
)
);
$minValue= min($array['price']);
$minKey=array_keys($array['price'], $minValue);
$tax_id=$array['tax_class_id'][$minKey[0]];
echo $tax_id;
This code will work for your issue. First i get the minimum value of nested array price and then it's associated key. After that i just access the nested array tax_class_id and get the value of the field i need like accessing every array.
$data = [
"tax_class_id" => [
12,
13,
13
],
"price" => [
6233,
3195,
19192
]
];
$lowestFound;
foreach($data["price"] as $i => $price){
if(!$lowestFound || $lowestFound[1] > $price)
$lowestFound = [$i,$price];
}
echo $data["tax_class_id"][$lowestFound[0]];
This code get tax_class_id of lowest price key in one cycle.
I think array_column gives you a nice output.
$array=Array
(
'tax_class_id' => Array(
0 => 12,
1 => 13,
2 => 13
),
'price' => Array(
0 => 6233,
1 => 3195,
2 => 19192
)
);
// Find minimum value
$min= min($array['price']);
// Find key of min value
$Key=array_search($min, $array['price']);
// Extract all values with key[min value]
$new = array_column($array, $Key);
Var_dump($new);
The output in $new will now be
array(2) {
[0]=> int(13)
[1]=> int(3195)
}
Basically both of the values you are looking for.
https://3v4l.org/NsdiS

using foreach loop to delete last element from associative array

I want to delete price index from each of the array.
Here is a sample code:
Array([0] => Array
(
[player_id] => 108
[trnmnt_team_id] => 1
[player_type] => 1
[user_team_id] => 11
[user_id] => 4
[price] => 10.00
)
[1] => Array
(
[player_id] => 151
[trnmnt_team_id] => 2
[player_type] => 1
[user_team_id] => 11
[user_id] => 4
[price] => 10.00
)
)
I tried to delete following way but it shown unexpected 'unset' (T_UNSET):
foreach ($mergeAllType as $key => $value) {
$price=$value;
$withOutPrice[]=unset($price['price']);
}
unset doesn't returns any value (it's language construct, not a function), you must do it following way:
unset($price['price']);
$withOutPrice[] = $price;
Tomas.lang's answer works fine if you know the last index's key. However if you don't know the name of the last key you could use the following:
unset(end($price));
$withOutPrice = $price;
You already got your answers regarding your foreach loop.
So, let me give you a different answer, using array_map and an anonymous function ;-)
<?php
$src = array(
array (
'player_id' => 108,
'trnmnt_team_id' => 1,
'player_type' => 1,
'user_team_id' => 11,
'user_id' => 4,
'price' => 10.00,
),
array (
'player_id' => 151,
'trnmnt_team_id' => 2,
'player_type' => 1,
'user_team_id' => 11,
'user_id' => 4,
'price' => 10.00,
),
);
$withOutPrice = array_map(
function($e) {
unset($e['price']);
return $e;
},
$src
);
var_export($withOutPrice);
If you want to unset() all off the price keys in your array you can use array_walk()
array_walk($arr, function(&$array) {
unset($array['price']);
});
Just replace $arr with whatever your arrays name is, i.e. $teams.
If you want to have two arrays, one with price and one without price you could duplicate the array before doing the above; i.e.
$teams = <DATASOURCE>
$teamsWithoutPrice = $teams;
array_walk($teamsWithoutPrice, function(&$array) {
unset($array['price']);
});
Then if you print out your $teamsWithoutPrice array you'll have your array with the price key removed.
Hope it helps.

Appending multiple values to associative array in PHP [duplicate]

This question already has answers here:
Merge two 2d arrays by shared column value
(6 answers)
Closed last month.
I would like to create a PHP array that will end up looking like this:
idPlayer namePlayer Points
1 John 20
2 Sam 25
3 Ben 22
But I would like to append the values not all at once:
First append the idPlayer and namePlayer
Then append the points for that idPlayer (I would have a $idPlayer variable to use each time I loop)
How could I do this in PHP?
I was thinking:
$myArray['idPlayer'] = "1";
$myArray['namePlayer'] = "John";
$myArray['Points'] = "20"
And then, how would I tell the array to go to the next row?
// output array
$myArray = array();
// your loop
while (something) {
// make an array for this iteration
$itarr = array();
// put stuff in it
$itarr['idPlayer'] = "1";
$itarr['namePlayer'] = "John";
$itarr['Points'] = "20"
// append it to output array using standard array indexing
$myArray[] = $itarr;
// OR, your own index
$myArray[$itarr['idPlayer']] = $itarr;
}
I dont know why you want to achieve such thing. But consider this example:
// like player table array initial
$players = array(
array(
'idPlayer' => 1,
'namePlayer' => 'John',
),
array(
'idPlayer' => 2,
'namePlayer' => 'Sam',
),
array(
'idPlayer' => 3,
'namePlayer' => 'Ben',
),
);
// data points to be added later (like points table)
$points = array(
array(
'idPlayer' => 1,
'Points' => 20,
),
array(
'idPlayer' => 2,
'Points' => 25,
),
array(
'idPlayer' => 3,
'Points' => 22,
),
);
$myArray = array();
foreach($players as $key => $value) {
foreach($points as $index => $element) {
// if this particular id matches the record inside points table then merge
if($value['idPlayer'] == $element['idPlayer']) {
$myArray[] = array('idPlayer' => $value['idPlayer'], 'namePlayer' => $value['namePlayer'], 'Points' => $element['Points']);
}
}
}
Should output something like: (can be used in a tabular data)
Array
(
[0] => Array
(
[idPlayer] => 1
[namePlayer] => John
[Points] => 20
)
[1] => Array
(
[idPlayer] => 2
[namePlayer] => Sam
[Points] => 25
)
[2] => Array
(
[idPlayer] => 3
[namePlayer] => Ben
[Points] => 22
)
)
Use the idPlayer as index:
$players = [
1 => [
'namePlayer' => 'John',
'points' => 20,
],
5 => [
'namePlayer' => 'Seth',
'points' => 25,
],
13 => [
'namePlayer' => 'Ben',
'points' => 35,
],
];
var_dump($players);
http://codepad.viper-7.com/nSXmZF
In php <5.4 use array() instead of [] constructor.

How to add new index and value from another array in PHP?

I need your help with my problem. My problem is I have 2 arrays the first one is the main array. The second is the array for my new data.
Let's say I have these arrays.
This is the main array:
Array
(
0 => Array
(
'id' => 1,
'name' => 'Apple',
'age' => 12
)
1 => Array
(
'id' => 2,
'name' => May,
'age' => 13
)
)
This is the second array:
Array
(
1 => Array
(
'gender' => 'Male'
)
2 => Array
(
'gender' => 'Female'
)
)
And I have this loop in PHP
foreach($main_array as &$main){
//this is the loop inside the first array
// how can I add the second array with it?
}
This is the sample output:
[0] => Array
(
[id] => 1
[name] => Apple
[age] => 12
[gender] => Female
)
[1] => Array
(
[id] => 2
[name] => May
[age] => 13
[gender] => Female
)
How can I do that? Any suggestions? That's all thanks.
for($i=0; $i<count($main_array); $i++){
for($j=0; $j<count($second_array); $j++){
if($main_array[$i]['id'] == $j){
$main_array[$i]['gender'] = $second_array[$j]['gender']
}
}
}
I fixed your example code, it wont run otherwise.
<?php
// Test data:
$main_array = Array(
0 => Array(
'id' => 1,
'name' => 'Apple',
'age' => 12
),
1 => Array (
'id' => 2,
'name' => 'May',
'age' => 13
)
);
$lookup = Array(
1 => Array(
'gender' => 'Male'
),
2 => Array(
'gender' => 'Female'
)
);
// Your answer:
foreach ($main_array as &$main) {
if (array_key_exists($main['id'],$lookup)) {
$main['gender'] = $lookup[$main['id']]['gender']; // <-- sets gender value
}
}
// Output it to browser:
echo '<pre>$main_array = '.print_r($main_array,true).'</pre>';
The array_key_exists() check is there to avoid errors such as PHP Notice: Undefined offset: 123 when the $lookup data is incomplete.
If you want to merge all of the data from both arrays:
PHP tools:
The exact behaviors of these functions needs to be studied and tested before usage, to make sure it fits your intent.
// array merge recursive doesn't merge numeric keys
$main_array = array_merge_recursive($main_array, $secondary_array);
// array replace recursive has a downside of replacing stuff
$main_array = array_replace_recursive($main_array, $secondary_array);
Rolling your own:
foreach($main_array as $i => &$main){
if(isset($secondary_array[$i])) {
foreach($secondary_array[$i] AS $key => $value) {
$main[$key] = $value;
}
}
}
Both of the above solutions only apply if the array-indexes of $main_array and $secondary_array match.
In your example your arrays don't match:
- $secondary_array[0] doesn't exist so $main_array[0] will not be populated with a 'gender' value;
- $main_array[2] doesn't exist so $main_array[2] will be created and it will only have a 'gender' value same as $secondary_array[2]['gender']
If you want to only merge some bits and pieces of the arrays:
Rolling your own:
foreach($main_array as $i => &$main) {
if(isset($secondary_array[$i])) and isset($secondary_array[$i]['gender'])) {
$main['gender'] = $secondary_array[$i]['gender'];
}
}
foreach($main_array as &$main){//this is the loop inside the first array
foreach($second_array as &$second){ //this is the loop inside the second array
}
}
foreach($arr1 as $k => $arr1Item) {
$arr1[$k]['gender'] = $arr2[$k]['gender'];
}

Categories