0

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.

2 Answers 2

1

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
                        )    
                )    
        )    
)
Sign up to request clarification or add additional context in comments.

1 Comment

You're welcome ;) I just noticed I forgot to sort the weeks array, you might have unordered results if your input array is not well ordered.
0

In an attempt to reduce loops and directly generate the nested result structure without post loop fixes, you'll find that references are used to populate the indexed subarrays within respective groups.

  1. Only push a new row into the result array when a name is encountered for the first time.

  2. When a week is encountered for the first time, a new column must be added to all data subarrays -- a default value of zero is applied.

Demo

$result = [];
foreach ($array as $row) {
    extract($row);
    if (!isset($seriesRefs[$name]['name'])) {
        $result['weeks'] ??= [];
        $seriesRefs[$name]['name'] = $name;
        $result['series'][] =& $seriesRefs[$name];
    }
    if (!isset($weekRefs[$name][$week])) {
        $result['weeks'][] = $week;
        $allNames ??= array_column($array, 'name', 'name');
        foreach ($allNames as $n) {
            $weekRefs[$n][$week] = 0;
            $seriesRefs[$n]['name'] ??= null;
            $seriesRefs[$n]['data'][] =& $weekRefs[$n][$week];
        }
    }
    $weekRefs[$name][$week] += $amount;
}
var_export($result);

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.