How to group subarrays by a column value?
Solution 1
There is no native one, just use a loop.
$result = array();
foreach ($data as $element) {
$result[$element['id']][] = $element;
}
Solution 2
You can try the following:
$group = array();
foreach ( $array as $value ) {
$group[$value['id']][] = $value;
}
var_dump($group);
Output:
array
96 =>
array
0 =>
array
'id' => int 96
'shipping_no' => string '212755-1' (length=8)
'part_no' => string 'reterty' (length=7)
'description' => string 'tyrfyt' (length=6)
'packaging_type' => string 'PC' (length=2)
1 =>
array
'id' => int 96
'shipping_no' => string '212755-1' (length=8)
'part_no' => string 'dftgtryh' (length=8)
'description' => string 'dfhgfyh' (length=7)
'packaging_type' => string 'PC' (length=2)
97 =>
array
0 =>
array
'id' => int 97
'shipping_no' => string '212755-2' (length=8)
'part_no' => string 'ZeoDark' (length=7)
'description' => string 's%c%s%c%s' (length=9)
'packaging_type' => string 'PC' (length=2)
Solution 3
In a more functional programming style, you could use array_reduce
$groupedById = array_reduce($data, function (array $accumulator, array $element) {
$accumulator[$element['id']][] = $element;
return $accumulator;
}, []);
Solution 4
I just threw this together, inspired by .NET LINQ
<?php
// callable type hint may be "closure" type hint instead, depending on php version
function array_group_by(array $arr, callable $key_selector) {
$result = array();
foreach ($arr as $i) {
$key = call_user_func($key_selector, $i);
$result[$key][] = $i;
}
return $result;
}
$data = array(
array(1, "Andy", "PHP"),
array(1, "Andy", "C#"),
array(2, "Josh", "C#"),
array(2, "Josh", "ASP"),
array(1, "Andy", "SQL"),
array(3, "Steve", "SQL"),
);
$grouped = array_group_by($data, function($i){ return $i[0]; });
var_dump($grouped);
?>
And voila you get
array(3) {
[1]=>
array(3) {
[0]=>
array(3) {
[0]=>
int(1)
[1]=>
string(4) "Andy"
[2]=>
string(3) "PHP"
}
[1]=>
array(3) {
[0]=>
int(1)
[1]=>
string(4) "Andy"
[2]=>
string(2) "C#"
}
[2]=>
array(3) {
[0]=>
int(1)
[1]=>
string(4) "Andy"
[2]=>
string(3) "SQL"
}
}
[2]=>
array(2) {
[0]=>
array(3) {
[0]=>
int(2)
[1]=>
string(4) "Josh"
[2]=>
string(2) "C#"
}
[1]=>
array(3) {
[0]=>
int(2)
[1]=>
string(4) "Josh"
[2]=>
string(3) "ASP"
}
}
[3]=>
array(1) {
[0]=>
array(3) {
[0]=>
int(3)
[1]=>
string(5) "Steve"
[2]=>
string(3) "SQL"
}
}
}
Solution 5
If you desire a Composer alternative with a full suite of tests, the array_group_by function achieves what you are looking for. Full disclosure: I am the author of said library.
$grouped = array_group_by($arr, 'id');
It also supports multi-level groupings, or even complex grouping through use of custom callback functions:
// Multilevel grouping
$grouped = array_group_by($arr, 'id', 'part_no');
// Grouping by a callback/callable function
$grouped = array_group_by($records, function ($row) {
return $row->city;
});
Comments
-
Red over 2 years
I have the following array
Array ( [0] => Array ( [id] => 96 [shipping_no] => 212755-1 [part_no] => reterty [description] => tyrfyt [packaging_type] => PC ) [1] => Array ( [id] => 96 [shipping_no] => 212755-1 [part_no] => dftgtryh [description] => dfhgfyh [packaging_type] => PC ) [2] => Array ( [id] => 97 [shipping_no] => 212755-2 [part_no] => ZeoDark [description] => s%c%s%c%s [packaging_type] => PC ) )
How can I group the array by
id
? Is there any native php functions are available to do this?While this approach works, I want to do this using a
foreach
, since with the above I will get duplicate items, which I'm trying to avoid?On the above example
id
have 2 items, so its need to be inside of theid
-
Red over 11 yearsKindly,__First i need to manipulate the array ? and then again foreach for the real purpose ?
-
fnagel over 7 yearsCan you give me a hint how to group by multiple fields? In my use case I have an object with a date field and need to group it by year, month and date. Something like { 2016 => { 09 => { 15 => $object } } }
-
Athari over 7 years@fnagel Nested grouping is somewhat complicated. See the support issue about nested groupBy. It includes a helper function
group_by_multiple
, as well as a lenghty explanation of how nested grouping works. With this function, your query will look likegroup_by_multiple($objects, [ '$v->date->format("Y")', '$v->date->format("n")', '$v->date->format("j")' ])
. -
DannyFeliz about 7 yearsWarning: This method
array_group_by
introduce the variable$key
as a method parameter and overridden in theforeach
-
fiberOptics about 5 yearshow does this know the similar ids?
-
mickmackusa almost 4 yearsBAKARI see these relevant posts: stackoverflow.com/a/47926978/2943403 and stackoverflow.com/a/61968973/2943403 and stackoverflow.com/a/52485161/2943403
-
mickmackusa almost 4 yearsThis answer is very wrong -- it is only returning the keys and will kill duplicates. It is also using the poor practice of calling
count()
on every iteration. Code-only answers are low-value on SO. I might never understand upvoters. -
Erdal G. almost 4 yearsYou forgot to
ksort($result, SORT_NUMERIC);
in the end. Question shows sorted keys -
mickmackusa almost 3 yearsIf that github link every dies or moves, this answer will be rendered useless. Your working solution should be fully/statically written in your answer. If you are the owner of the code being referenced, you are expected to make explicit attribution. Please edit your answer.
-
mickmackusa almost 3 yearsIn your custom function,
$groupKey = null;
is useless because it is unconditionally overwritten.elseif
should be one word in PHP. Doesfunc_num_args()
really need to be called more than once? -
Jake Z almost 3 years@mickmackusa I have updated the answer to reflect ownership of the linked library. This is a mistake that I admit. To your other points, I disagree that a full written example is necessary. While possible, it is not practical to copy 50 lines of code into Stack Overflow when the entire point is to provide a library/Composer alternative to untested and limited code. Composer was a pivotal moment for PHP, and without it PHP would be a maintenance nightmare for sufficiently large applications.
-
Jake Z almost 3 years@mickmackusa Per the
$groupKey
comment, it is not useless. It is good practice to initialize variables even if PHP does not make it necessary. PHP's own manual states as much. Further, in many languages, variables created in nested statements are not available outside of that nesting. Yes,func_num_args
need not technically be called if the length is passed through recursive calls and is subtracted on each nesting, but that micro optimization results in less readable code for very few gains. -
mickmackusa almost 3 years"_ It is good practice to initialize variables even if PHP does not make it necessary._" Yes, if it is possible that it will not be declared before it is access. In this case, you are unconditionally overwriting the
null
value -- see how that is a wasted action? It is good practice to store a value in a variable when you will use it more than once. When you already have a 50line function why claim that you are fighting against bloat when you are making redundant function calls? Can your library make use the splat operator to modernize the script? -
mickmackusa almost 3 yearsStack Overflow will show your script to a limited height if you post it here. This means that researchers won't need to "link chase" to see the code behind your suggestion.
-
mickmackusa almost 3 yearsIterated calls of
in_array()
is not best practice. -
Jake Z almost 3 yearsIt is good practice whether it is overwritten by nested code or not. Again, many other languages (e.g. JavaScript and Python) require a variable to be initialized, even if it will be immediately overwritten by nested code. That PHP supports uninitialized variables is irrelevant when we want portable code that conforms to best practices. If the conditionals were just an
if/else
, a ternary operator could be used, but that is not the case here. A couple lines in an imported library is hardly bloat. You again miss the main reason: maintainability and portability. -
Jake Z almost 3 yearsThis is polluting the comments and I request that this unproductive discussion stop. We clearly disagree. I do not think someone posting the library of
react-select
in its entirety to a Stack Overflow question about the proper React component for select lists is desirable, for example. -
Alex78191 over 2 years@DannyFeliz What does it mean?
-
Alex78191 over 2 yearsHow does detecting the unique rows relate to grouping?
-
mickmackusa about 2 years@fiberOptics The result array unconditionally pushes newly indexed elements into each group (grouped explicitly by
$element['id']
. This question could use a bit more explanation for researchers that are inexperienced with this technique/language.