Reputation: 3
I am trying to group an array by it's values. Below is my array:
$array = Array ( 0 => Array ( 'name' => 'John Doe', 'age' => '36', 'code' => '437', 'group' => '1000', ), 1 => Array ( 'name' => 'John Doe', 'age' => '36', 'code' => '437', 'group' => '7777', ), 2 => Array ( 'name' => 'John Doe', 'age' => '36', 'code' => '437', 'group' => '7777', ), 3 => Array ( 'name' => 'John Doe', 'age' => '36', 'code' => '437', 'group' => '4000', ), 4 => Array ( 'name' => 'John Doe', 'age' => '36', 'code' => '437', 'group' => '4000', ), 5 => Array ( 'name' => 'John Doe', 'age' => '36', 'code' => '437', 'group' => '5000', ), 6 => Array ( 'name' => 'John Doe', 'age' => '36', 'code' => '437', 'group' => '6000', ), 7 => Array ( 'name' => 'John Doe', 'age' => '36', 'code' => '437', 'group' => '6000', ), );
I have tried below:
$result = array();
foreach ($array as $key => $record) {
if (!isset($result[$record['code']])) {
$result[$record['code']] = array(
'name' => $record['name'],
'age' => $record['age'],
'groups' => array(array($record['code'], $record['group'])),
);
}
else {
$result[$record['code']]['groups'][] = array($record['code'],$record['group']);
}
}
$result = array_values($result);
print_r($result);
And I am getting:
Array ( [0] => Array ( [name] => John Doe [age] => 36 [groups] => Array ( [0] => Array ( [0] => 437 [1] => 1000 ) [1] => Array ( [0] => 437 [1] => 7777 ) [2] => Array ( [0] => 437 [1] => 7777 ) [3] => Array ( [0] => 437 [1] => 4000 ) [4] => Array ( [0] => 437 [1] => 4000 ) [5] => Array ( [0] => 437 [1] => 5000 ) [6] => Array ( [0] => 437 [1] => 6000 ) [7] => Array ( [0] => 437 [1] => 6000 ) ) ) )
Now, I want my array to be grouped by the values of group 7777, 1000 and others(all others group values):
Array ( [0] => Array ( [name] => John Doe [age] => 36 [7777] => Array ( [0] => Array ( [0] => 437 [1] => 7777 ) [1] => Array ( [0] => 437 [1] => 7777 ) ) [6000] => Array ( [0] => Array ( [0] => 437 [1] => 6000 ) [1] => Array ( [0] => 437 [1] => 6000 ) ) [others] => Array ( [0] => Array ( [0] => 437 [1] => 1000 ) [1] => Array ( [0] => 437 [1] => 4000 ) [2] => Array ( [0] => 437 [1] => 4000 ) [3] => Array ( [0] => 437 [1] => 5000 ) ) ) )
Upvotes: 0
Views: 6455
Reputation: 47864
I am not sure what your business logic is, but your data storage design is not optimal. Redundant levels and values can and should be removed as a matter of best practices. That advice aside, Mickael's solution will possibly let you down if your input array is not pre-sorted on code
values and you have more than one code
value.
The process is very straight forward. Use code
values as temporary unique keys in your output array. If dealing with the first occurrence of a code
value, set the name
and age
elements. On every iteration, add a new subarray to the output array based on the code
value and the group
value condition. When the loop finishes, reindex the output array with array_values()
.
Code: (Demo)
$array = [
['name' => 'John Doe', 'age' => '36', 'code' => '437', 'group' => '1000'],
['name' => 'John Doe', 'age' => '36', 'code' => '437', 'group' => '7777'],
['name' => 'John Doe', 'age' => '36', 'code' => '437', 'group' => '7777'],
['name' => 'John Doe', 'age' => '36', 'code' => '437', 'group' => '4000'],
['name' => 'John Doe', 'age' => '36', 'code' => '437', 'group' => '4000'],
['name' => 'John Doe', 'age' => '36', 'code' => '437', 'group' => '5000'],
['name' => 'John Doe', 'age' => '36', 'code' => '437', 'group' => '6000'],
['name' => 'John Doe', 'age' => '36', 'code' => '437', 'group' => '6000']
];
foreach ($array as $row) {
if (!isset($result[$row['code']])) {
$result[$row['code']] = ['name' => $row['name'], 'age' => $row['age']];
}
$result[$row['code']][in_array($row['group'], ['7777','6000']) ? $row['group'] : 'others'][] = [$row['code'], $row['group']];
}
var_export(array_values($result));
Output:
array (
0 =>
array (
'name' => 'John Doe',
'age' => '36',
'others' =>
array (
0 =>
array (
0 => '437',
1 => '1000',
),
1 =>
array (
0 => '437',
1 => '4000',
),
2 =>
array (
0 => '437',
1 => '4000',
),
3 =>
array (
0 => '437',
1 => '5000',
),
),
7777 =>
array (
0 =>
array (
0 => '437',
1 => '7777',
),
1 =>
array (
0 => '437',
1 => '7777',
),
),
6000 =>
array (
0 =>
array (
0 => '437',
1 => '6000',
),
1 =>
array (
0 => '437',
1 => '6000',
),
),
),
)
Upvotes: 1
Reputation: 3440
Try this :
// Create a new array
$result = array();
// Loop through your array
foreach ($array as $value) {
// Create a key that start at 0
$i = 0;
// Test if $result[0] exist : if yes, you have data, else you have nothing
if (isset($result[$i])) {
do {
// Check if the 'name' is new : if yes, $i++ to check next name
if ($result[$i]['name'] !== $value['name']) $i++;
// If you find similar name, stop here
else break;
} while (isset($result[$i]));
// Just add $result[0] with name and age value
} else {
$result[$i] = array (
'name' => $value['name'],
'age' => $value['age']
);
}
// Now you know the index of result you need to work with
// Just add a new code / group array to your code index
$result[$i][$value['group']][] = array($value['code'], $value['group']);
}
If you do var_dump($result);
the output is :
array (size=1)
0 =>
array (size=7)
'name' => string 'John Doe' (length=8)
'age' => string '36' (length=2)
1000 =>
array (size=1)
0 =>
array (size=2)
0 => string '437' (length=3)
1 => string '1000' (length=4)
7777 =>
array (size=2)
0 =>
array (size=2)
0 => string '437' (length=3)
1 => string '7777' (length=4)
1 =>
array (size=2)
0 => string '437' (length=3)
1 => string '7777' (length=4)
4000 =>
array (size=2)
0 =>
array (size=2)
0 => string '437' (length=3)
1 => string '4000' (length=4)
1 =>
array (size=2)
0 => string '437' (length=3)
1 => string '4000' (length=4)
5000 =>
array (size=1)
0 =>
array (size=2)
0 => string '437' (length=3)
1 => string '5000' (length=4)
6000 =>
array (size=2)
0 =>
array (size=2)
0 => string '437' (length=3)
1 => string '6000' (length=4)
1 =>
array (size=2)
0 => string '437' (length=3)
1 => string '6000' (length=4)
EDIT :
To get only group value equal to 7777
and 6000
replace
$result[$i][$value['group']][] = array($value['code'], $value['group']);
by
$group_value = $value['group'] == "7777" || $value['group'] == "6000" ? $value['group'] : "Others";
$result[$i][$group_value][] = array($value['code'], $value['group']);
Now the output of var_dump($result);
is :
array (size=1)
0 =>
array (size=5)
'name' => string 'John Doe' (length=8)
'age' => string '36' (length=2)
'Others' =>
array (size=4)
0 =>
array (size=2)
0 => string '437' (length=3)
1 => string '1000' (length=4)
1 =>
array (size=2)
0 => string '437' (length=3)
1 => string '4000' (length=4)
2 =>
array (size=2)
0 => string '437' (length=3)
1 => string '4000' (length=4)
3 =>
array (size=2)
0 => string '437' (length=3)
1 => string '5000' (length=4)
7777 =>
array (size=2)
0 =>
array (size=2)
0 => string '437' (length=3)
1 => string '7777' (length=4)
1 =>
array (size=2)
0 => string '437' (length=3)
1 => string '7777' (length=4)
6000 =>
array (size=2)
0 =>
array (size=2)
0 => string '437' (length=3)
1 => string '6000' (length=4)
1 =>
array (size=2)
0 => string '437' (length=3)
1 => string '6000' (length=4)
Is it what you want?
Upvotes: 0
Reputation: 23958
Here is one method that heavily relies on array_intersect if I may say it myself.
This is to make sure the number of loops is keept as low as possible.
I loop only the unique names, and the unique groups within that name.
$names = array_column($array, "name");
$groups = array_column($array, "group");
foreach(array_unique($names) as $name){
$intersects = array_intersect_key($array, array_intersect($names, [$name]));
$new[$name] = ["name" => $name, "age" => end($intersects)["age"]]; // Create the start of the array
foreach(array_unique($groups) as $group){ // loop only unique groups
$intersects = array_intersect_key($array, array_intersect($groups, [$group])); // find matching arrays with this group
foreach($intersects as $int){
$temp = array_diff($int, ["name" => $new[$name]["name"], "age" => $new[$name]["age"]]); // remove the name and age from the matching array and place them in 6000/7777 or others
if($temp["group"] == "6000" || $temp["group"] == "7777"){
$new[$name][$group][] = $temp;
}else{
$new[$name]["others"][] = $temp;
}
}
}
}
var_dump($new);
output:
array(1) {
["John Doe"]=>
array(5) {
["name"]=>
string(8) "John Doe"
["age"]=>
string(2) "36"
["others"]=>
array(4) {
[0]=>
array(2) {
["code"]=>
string(3) "437"
["group"]=>
string(4) "1000"
}
[1]=>
array(2) {
["code"]=>
string(3) "437"
["group"]=>
string(4) "4000"
}
[2]=>
array(2) {
["code"]=>
string(3) "437"
["group"]=>
string(4) "4000"
}
[3]=>
array(2) {
["code"]=>
string(3) "437"
["group"]=>
string(4) "5000"
}
}
[7777]=>
array(2) {
[0]=>
array(2) {
["code"]=>
string(3) "437"
["group"]=>
string(4) "7777"
}
[1]=>
array(2) {
["code"]=>
string(3) "437"
["group"]=>
string(4) "7777"
}
}
[6000]=>
array(2) {
[0]=>
array(2) {
["code"]=>
string(3) "437"
["group"]=>
string(4) "6000"
}
[1]=>
array(2) {
["code"]=>
string(3) "437"
["group"]=>
string(4) "6000"
}
}
}
}
EDIT changed 1000 to 6000 as read in comments to other answer.
Upvotes: 0