phparraysmultidimensional-arraygroupingsub-array

Isolate unique values from a column of a 2d array and group other columns into subarrays


I have an array that looks like this:

Array
(
[0] => Array
    (
        [amount] => 75.00
        [name] => CLIENT1
        [week] => 22
    )

[1] => Array
    (
        [amount] => 945.00
        [name] => CLIENT1
        [week] => 23
    )

[2] => Array
    (
        [amount] => 45.00
        [name] => CLIENT1
        [week] => 24
    )
...

[15] => Array
    (
        [amount] => 45.00
        [name] => CLIENTX
        [week] => 22
    )

[16] => Array
    (
        [amount] => 15.00
        [name] => CLIENTX
        [week] => 22
    )
// HAS NO VALUE IN WEEK 23 BUT TWO IN WEEK 22!!!
[17] => Array
    (
        [amount] => 73.00
        [name] => CLIENTX
        [week] => 24
    )

I need an array that looks like this

Array
(
['weeks'] => Array (22,23,24) //ALL WEEKS FOUND SOMEWHERE
['series'] => Array
           (
           [0] => Array
               (
                 ['name'] => 'CLIENT1'
                 ['data'] => Array (75.00, 945.00, 45.00)
               )
           [1] => Array
               (
                 ['name'] => 'CLIENTX'
                 ['data'] => Array (60.00, 0, 73.00)
               )
          )
)

First try

This is rather a logical problem, not a matter of programming, but I am stuck from looking at it for so long now.

The ['weeks'] => Array (22,23,24) shouldn't be a problem, but the rest really is.

The closest I got so far is this:

$clientArray = array();
$weekAmount = array();
foreach($hours as $hour){
    /* For better readability */
    $client = $hour['name'];
    $amount = $hour['amount'];
    $week = $hour['week'];

    if(!array_key_exists($week, $weekAmount)){
        $weekAmount[$week] = 0;
    }
    $weekAmount[$week] = $amount;
    $clientArray[$client] = $weekAmount;
    ksort($clientArray[$client]); // to order by weeks
}

But this does not add up values from the same week and I need to loop through this again and I don't know how to find the "missing" weeks and set 0 as the according value.


Solution

  • There must be a more efficient way than this, but at least it works :

    <?php
    
    $input = array(
        array('amount'  => 75.00,
              'name'    => 'CLIENT1',
              'week'    => 22),
        array('amount'  => 945.00,
              'name'    => 'CLIENT1',
              'week'    => 23),
        array('amount'  => 45.00,
              'name'    => 'CLIENT1',
              'week'    => 24),
        array('amount'  => 45.00,
              'name'    => 'CLIENTX',
              'week'    => 22),
        array('amount'  => 15.00,
              'name'    => 'CLIENTX',
              'week'    => 22),
        array('amount'  => 73.00,
              'name'    => 'CLIENTX',
              'week'    => 24),
    );
    
    $weeks = array();
    $names = array();
    foreach ($input as $v) {
        if (!isset($weeks[$v['week']]))
            $weeks[$v['week']] = array();
        if (!isset($names[$v['name']]))
            $names[$v['name']] = array();
        if (!isset($names[$v['name']][$v['week']]))
            $names[$v['name']][$v['week']] = 0;
        $names[$v['name']][$v['week']] += $v['amount'];
    }
    
    $output = array('weeks' => array(), 'series' => array());
    foreach ($weeks as $week=>$values) {
        $output['weeks'][] = $week;
    }
    foreach ($names as $name=>$data) {
        $serie = array();
        $serie['name'] = $name;
        foreach ($weeks as $week=>$values) {
            if (isset($data[$week]))
                $serie['data'][] = $data[$week];
            else
                $serie['data'][] = 0;
        }
        $output['series'][] = $serie;
    }
    
    echo '<pre>'; print_r($output);
    ?>
    

    Returns :

    Array
    (
        [weeks] => Array
            (
                [0] => 22
                [1] => 23
                [2] => 24
            )
        [series] => Array
            (
                [0] => Array
                    (
                        [name] => CLIENT1
                        [data] => Array
                            (
                                [0] => 75
                                [1] => 945
                                [2] => 45
                            )
    
                    )    
                [1] => Array
                    (
                        [name] => CLIENTX
                        [data] => Array
                            (
                                [0] => 60
                                [1] => 0
                                [2] => 73
                            )    
                    )    
            )    
    )