0

I've searched a lot of examples with group/sum array values - unfortunately I can't resolve my problem. I got array $data which looks like this:

Array
(
    [0] => Array
        (
            [0] => 1
            [1] => 2014
            [context] => 'aaa'
        )

    [1] => Array
        (
            [0] => 12
            [1] => 2014
            [context] => 'aaa'
        )       

    [2] => Array
        (
            [0] => 5
            [1] => 2014
            [context] => 'zzz'
        )               
)

I would like to group and sum its values (but not all) by 'context'.

So desired output is:

Array
(
    [0] => Array
        (
            [0] => 13
            [1] => 2014
            [context] => 'aaa'
        )

    [1] => Array
        (
            [0] => 5
            [1] => 2014
            [context] => 'zzz'
        )       

)

I'm far from this expected output. I've tried something like:

$result = array();
foreach ($data as $subArray) 
{
  foreach ($subArray as $row)
  {
    $result[$row['context']] = $row['context'];
    $result[$row['1']] = $row['1'];
    $result[$row['0']] += $row['0'];
  }
}

But of course it doesn't work and I'm out of ideas. Can you please give me a hint? What else can I try?

3 Answers 3

1

The problem is you were overwriting elements in your loop and you were counting on an extra nesting level:

$data = array(
    0 => array(
            0 => 1,
            1 => 2014,
            'context' => 'aaa'
        ),

    1 => array(
            0 => 12,
            1 => 2014,
            'context' => 'aaa'
        ),       

    2 => array(
            0 => 5,
            1 => 2014,
            'context' => 'zzz'
        )               
);

$result = array();

// the elements to sum - since everything is mixed together.
// the values in this array should be the index you want to sum
// ex. $sum = array(2,3) would sum $data[2] and $data[3]
$sum = array(0);

foreach ($data as $subArray) 
{
  $context = $subArray['context'];

  if (!isset($result[$context])) {
    // initialize the result for this context because it doesnt exist yet
    $result[$context] = array();
  }

  // you had an extra nesting level here
  // $row was equiv to 'aaa' or '2014' whereas you thought it was
  // array('context' => 'aaa', 0 => 5, 1 => '2014')
  foreach ($subArray as $idx => $val)
  {
    // you were also constantly overrwriting $result'aaa'] (or whatever context) here
    if (in_array($idx, $sum)) {
       $result[$context][$idx] = isset($result[$context][$idx])
         ? $result[$context][$idx] + $val
         : $val;
    } else {
      // this will keep overwriting anything that isnt in the $sum array
      // but thats ok because those values should be the same with, or the last
      // one should win. If you need different logic than that then adjsut as necessary
      $result[$context][$idx] = $val;
    }
  }
}

printf('<pre>%s</pre>', print_r($result, true));
Sign up to request clarification or add additional context in comments.

4 Comments

It works great except for one issue: if I would like to sum more then 1 element, for instance: $sum = array(0 => 2, 1 => 3); //etc always element for index 0 is also summed up. I know that question was little bit different, but is it possible to sum other element than this with index 0? Is it a good solution: if ($idx === 0) {$result[$context][$idx] = $val;} ?
Yeah actually thats my fault at one point i was using array_intersect_key so the keys in $sum were the indexes in $subArray you wanted to sum. But then i switched to in_array... should be corrected now.
it's not :) Still value with index 0 is summed.
@suz: I just tested it again locally and it seems to be working for me just fine. Can you post a new question with your updated code, or a link to a phpfiddle or something?
1

You can done it using an temporary array(here $newArr). Can try something like this

$newArr = array();
foreach($your_arr as $key=>$val){
    $index = $val['context'].$val[1];
    if(isset($newArr[$index])){
        $val_0 = $newArr[$val['context'].$val[1]][0] + $val[0];
        $newArr[$val['context'].$val[1]] = array($val_0, $val[1], 'context'=>$val['context']);
    }else{
        $newArr[$val['context'].$val[1]] = $val;
    }
}
$result = array_values($newArr);
print '<pre>';
print_r($result);
print '</pre>';

Comments

0

Use a single loop and add a reference on the first element of the first encountered row with a given context value. If a context value is encountered more than once, add its first element's value to the reference and unset the entire row.

Code: (Demo)

foreach ($array as $i => &$row) {
    if (!isset($ref[$row['context']])) {
        $ref[$row['context']] = &$row[0];  // create reference
    } else {
        $ref[$row['context']] += $row[0];  // sum new value and reference value
        unset($array[$i]);                 // remove the unneeded row
    }
}
var_export($array);

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.