简体   繁体   中英

Grouping a 2D array according to its values

I've been trying to get some display logic to behave and stay where it belongs and the code has turned into an interesting little problem that'd be nice to make a general solution for.

Bear with me, it looks like a wall of text but I've tried to format it nicely with simple example data so it should be understandable after a quick skim through.

If for some reason this whole thing is a terrible idea, I need telling before I create an affront to the gods.

Starting with data like this, for example:

$data = array(

    array(
        'name' => 'Dave',
        'age'  => '21',
        'city' => 'New York',
    ),
    array(
        'name' => 'Mike',
        'age'  => '19',
        'city' => 'Chicago',
    ),
    array(
        'name' => 'John',
        'age'  => '21',
        'city' => 'Chicago',
    ),
    array(
        'name' => 'Matt',
        'age'  => '19',
        'city' => 'New York',
    ),
    array(
        'name' => 'Luke',
        'age'  => '21',
        'city' => 'New York',
    ),

);

With an array of key names by which to group the data, such as

$groups = array('city', 'age);

The data then becomes:

$data = array(

    'New York' => array(
        '21' => array(
            array(
                'name' => 'Dave',
                'age'  => '21',
                'city' => 'New York',
            ),
            array(
                'name' => 'Luke',
                'age'  => '21',
                'city' => 'New York',
            ),
        ),
        '19' => array(
            array(
                'name' => 'Matt',
                'age'  => '19',
                'city' => 'New York',
            ),
        ),
    ),
    'Chicago' => array(
        '19' => array(
            array(
                'name' => 'Mike',
                'age'  => '19',
                'city' => 'Chicago',
            ),
        ),
        '21' => array(
            array(
                'name' => 'John',
                'age'  => '21',
                'city' => 'Chicago',
            ),
        ),
    ),
);

When I say "general solution", I mean I'm trying to make something that can group things to any nesting level depending on how many of the key names you ask it to group by.

It feels like the sort of problem that I could solve instantly if I just knew some random esoteric bit of PHP syntax. Any suggestions? I'll try to update this is if I figure it out in the meantime.

function group_array($arr, $fields) {

    if(empty($fields) || !is_array($fields)) {
        return $arr;
    }

    $newarr = array(); // so that we always return an array
    $field = array_shift($fields);

    foreach($arr as $val) {
        $newarr[$val[$field]][] = $val;
    }

    foreach(array_keys($newarr) as $key) {
        // Since we shifted one field off before, this groups by the remaining
        $newarr[$key] = group_array($newarr[$key], $fields);
    }

    return $newarr;
}

I know this is old but wanted to post a solution for others when they come to it.

foreach($data as $row) {
     $data_array[$row['city']][] = $row;
}

I was originally trying to sort arrays of objects so since I was gonna write it anyway, here's one that works on objects, even if it is a slightly hacky idea

function group_objects($array, $fields)
{
    if (empty($fields) || !is_array($fields)) {
        return $array;
    }

    $newArray = array();
    $field    = array_shift($fields);

    foreach ($array as $object) {
        $key = call_user_func(array($object, 'get' . ucwords($field)));
        $newArray[$key][] = $object;
    }

    foreach (array_keys($newArray) as $key) {
        $newArray[$key] = group_objects($newArray[$key], $fields);
    }

    return $newArray;
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM