Group array by subarray values

113,013

Solution 1

$arr = array();

foreach ($old_arr as $key => $item) {
   $arr[$item['id']][$key] = $item;
}

ksort($arr, SORT_NUMERIC);

Solution 2

foreach($array as $key => $value){
   $newarray[$value['id']][$key] = $value;
}

var_dump($newarray);

piece of cake ;)

Solution 3

The following code adapts @Tim Cooper’s code to mitigate Undefined index: id errors in the event that one of the inner arrays doesn’t contain an id:

$arr = array();

foreach($old_arr as $key => $item)
{
    if(array_key_exists('id', $item))
        $arr[$item['id']][$key] = $item;
}

ksort($arr, SORT_NUMERIC);

However, it will drop inner arrays without an id.

E.g.

$old_arr = array(
    'a' => array ( 'id' => 20, 'name' => 'chimpanzee' ),
    'b' => array ( 'id' => 40, 'name' => 'meeting' ),
    'c' => array ( 'id' => 20, 'name' => 'dynasty' ),
    'd' => array ( 'id' => 50, 'name' => 'chocolate' ),
    'e' => array ( 'id' => 10, 'name' => 'bananas' ),
    'f' => array ( 'id' => 50, 'name' => 'fantasy' ),
    'g' => array ( 'id' => 50, 'name' => 'football' ),
    'h' => array ( 'name' => 'bob' )
);

will drop the 'h' array completely.

Solution 4

You can also use Arrays::groupBy() from ouzo-goodies:

$groupBy = Arrays::groupBy($array, Functions::extract()->id);

print_r($groupBy);

And result:

Array
(
    [20] => Array
        (
            [0] => Array
                (
                    [id] => 20
                    [name] => chimpanzee
                )

            [1] => Array
                (
                    [id] => 20
                    [name] => dynasty
                )

        )

    [40] => Array
        (
            [0] => Array
                (
                    [id] => 40
                    [name] => meeting
                )

        )

    [50] => Array
        (
            [0] => Array
                (
                    [id] => 50
                    [name] => chocolate
                )

            [1] => Array
                (
                    [id] => 50
                    [name] => fantasy
                )

            [2] => Array
                (
                    [id] => 50
                    [name] => football
                )

        )

    [10] => Array
        (
            [0] => Array
                (
                    [id] => 10
                    [name] => bananas
                )

        )

)

And here are the docs for Arrays and Functions.

Solution 5

Here is a function that will take an array as the first argument and a criteria (a string or callback function) as the second argument. The function returns a new array that groups the array as asked for.

/**
 * Group items from an array together by some criteria or value.
 *
 * @param  $arr array The array to group items from
 * @param  $criteria string|callable The key to group by or a function the returns a key to group by.
 * @return array
 *
 */
function groupBy($arr, $criteria): array
{
    return array_reduce($arr, function($accumulator, $item) use ($criteria) {
        $key = (is_callable($criteria)) ? $criteria($item) : $item[$criteria];
        if (!array_key_exists($key, $accumulator)) {
            $accumulator[$key] = [];
        }

        array_push($accumulator[$key], $item);
        return $accumulator;
    }, []);
}

Here is the given array:

$arr = array(
    'a' => array ( 'id' => 20, 'name' => 'chimpanzee' ),
    'b' => array ( 'id' => 40, 'name' => 'meeting' ),
    'c' => array ( 'id' => 20, 'name' => 'dynasty' ),
    'd' => array ( 'id' => 50, 'name' => 'chocolate' ),
    'e' => array ( 'id' => 10, 'name' => 'bananas' ),
    'f' => array ( 'id' => 50, 'name' => 'fantasy' ),
    'g' => array ( 'id' => 50, 'name' => 'football' )
);

And examples using the function with a string and a callback function:

$q = groupBy($arr, 'id');
print_r($q);

$r = groupBy($arr, function($item) {
    return $item['id'];
});
print_r($r);

The results are the same in both examples:

Array
(
    [20] => Array
        (
            [0] => Array
                (
                    [id] => 20
                    [name] => chimpanzee
                )

            [1] => Array
                (
                    [id] => 20
                    [name] => dynasty
                )

        )

    [40] => Array
        (
            [0] => Array
                (
                    [id] => 40
                    [name] => meeting
                )

        )

    [50] => Array
        (
            [0] => Array
                (
                    [id] => 50
                    [name] => chocolate
                )

            [1] => Array
                (
                    [id] => 50
                    [name] => fantasy
                )

            [2] => Array
                (
                    [id] => 50
                    [name] => football
                )

        )

    [10] => Array
        (
            [0] => Array
                (
                    [id] => 10
                    [name] => bananas
                )

        )

)

Passing the callback is overkill in the example above, but using the callback finds its use when you pass in an array of objects, a multidimensional array, or have some arbitrary thing you want to group by.

Share:
113,013
Anson Kao
Author by

Anson Kao

Hi! My name is Anson, and I'm based out of Toronto. I'm an entrepreneur with a decade-long background in technology, startups, and more recently: video. I love bringing people together to create the future.

Updated on July 08, 2022

Comments

  • Anson Kao
    Anson Kao almost 2 years

    I have an array of subarrays in the following format:

    array
    (
        a => array ( id = 20, name = chimpanzee )
        b => array ( id = 40, name = meeting )
        c => array ( id = 20, name = dynasty )
        d => array ( id = 50, name = chocolate )
        e => array ( id = 10, name = bananas )
        f => array ( id = 50, name = fantasy )
        g => array ( id = 50, name = football )
    )
    

    And I would like to group it into a new array based on the id field in each subarray.

    array
    (
        10 => array
              (
                e => array ( id = 10, name = bananas )
              )
        20 => array
              (
                a => array ( id = 20, name = chimpanzee )
                c => array ( id = 20, name = dynasty )
              )
        40 => array
              (
                b => array ( id = 40, name = meeting )
              )
        50 => array
              (
                d => array ( id = 50, name = chocolate )
                f => array ( id = 50, name = fantasy )
                g => array ( id = 50, name = football )
              )
    )
    
  • mickmackusa
    mickmackusa almost 4 years
    This is an "invented problem" -- not represented in the OP's question. Probably better to find another question which poses this problem and post it there.