Search code examples
phparraysmultidimensional-arraygroupingcounting

Group data from a 2d array by a column and count the unique values of another column per group


I have an array that looks like this:

$cars = array (
  array(
    'a' => 'audi',
    'b' => 'a4'),
  array(
    'a' => 'peugeot',
    'b' => '306'),
  array(
    'a' => 'audi',
    'b' => 'a4'),
  array(
    'a' => 'audi',
    'b' => 'a5'),
  array(
    'a' => 'peugeot',
    'b' => '106'),
  array(
    'a' => 'peugeot',
    'b' => '106'),
);

I need to order arrays like this to (id is the same as name):

name => audi
id=> audi
data => a4 => 2
        a5 => 1
name => peugeot
id=> peugeot
data => 306 => 1
        106 => 2

So the car brands need to be grouped an the car types counted.

I already have this code; but that is only for the group part and the count part is missing.

function mergeAndOrder($data){

    // set group arrays
    $i = 0; $group1 = array();

    // loop trough array
    $array = array(); $array2 = array();        
    if($data != null){
        foreach($data AS $row){

            // search and order level1
            $search = array_search($row->a,$group1);

            // this object is not found
            if(is_int($search) == false){

                $group1[$i] = $row->a;
                $array[$i]['id'] = $row->a;
                $array[$i]['name'] = $row->a;
                $array[$i]['data'] = array();

                $i++;   

            }               

        }                               
    }

    return $array;
}

Does somebody know an solution for this case? Thanks!

--- INPUT (part of) --- a = lease company in this case

Array
(
    [0] => stdClass Object
        (
            [b] => AUDI
            [a] => LPN
        )

    [1] => stdClass Object
        (
            [b] => AUDI
            [a] => LPN
        )

    [2] => stdClass Object
        (
            [b] => AUDI
            [a] => LPN
        )

    [3] => stdClass Object
        (
            [b] => AUDI
            [a] => LPN
        )

--- OUTPUT (part of) ---

Array
(
    [0] => Array
        (
            [id] => LPN
            [name] => LPN
            [data] => Array
                (
                )

        )

    [1] => Array
        (
            [id] => ARV
            [name] => ARV
            [data] => Array
                (
                )

        )

    [2] => Array
        (
            [id] => ARVB
            [name] => ARVB
            [data] => Array
                (
                )

        )

    [3] => Array
        (
            [id] => LPD
            [name] => LPD
            [data] => Array
                (
                )

        )

)

Array
(
    [0] => Array
        (
            [id] => LPN
            [name] => LPN
            [data] => Array
                (
                )

        )

    [1] => Array
        (
            [id] => ARV
            [name] => ARV
            [data] => Array
                (
                )

        )

    [2] => Array
        (
            [id] => ARVB
            [name] => ARVB
            [data] => Array
                (
                )

        )

Solution

  • If I understand your question correctly, this should do what you want.

    function mergeAndOrder ($data) {
    
        $output = array();
        foreach ($data as $item) {
    
            $id    = $item->a;
            $value = $item->b;
    
            if (!array_key_exists($id, $output)) {
                $output[$id] = array('id' => $id, 'name' => $id, 'data' => array());
            }
    
            if (!array_key_exists($value, $output[$id]['data'])) {
                $output[$id]['data'][$value] = 0;
            }
    
            $output[$id]['data'][$value]++;
        }
    
        // Order by name element
        uasort($output, function ($a, $b) {
            return strcasecmp($a['name'], $b['name']);
        });
    
        return $output;
    }
    

    Output:

    Array
    (
        [audi] => Array
            (
                [id] => audi
                [name] => audi
                [data] => Array
                    (
                        [a4] => 2
                        [a5] => 1
                    )
    
            )
    
        [peugeot] => Array
            (
                [id] => peugeot
                [name] => peugeot
                [data] => Array
                    (
                        [306] => 1
                        [106] => 2
                    )
    
            )
    )