4

i'm trying to figure out how to sum certain values of a multi-dimensional array if they have similar dates.

Here's my array:

<?$myArray=array(

array(
        'year' => 2011,
        'month ' => 5,
        'day' => 13,
        'value' => 2
    ),
array(
        'year' => 2011,
        'month '=> 5,
        'day' => 14,
        'value' => 5
    ),
array(
        'year' => 2011,
        'month ' => 5,
        'day' => 13,
        'value' => 1
    ),
array(
        'year' => 2011,
        'month ' => 5,
        'day' => 14,
        'value' => 9
    )
);?>

here's how i'd like the output to look:

<?$output=array(

array(
        'year' => 2011,
        'month ' => 5,
        'day' => 13,
        'value' => 3 //the sum of 1+2
    ),
array(
        'year' => 2011,
        'month '=> 5,
        'day' => 14,
        'value' => 14 //the sum of 5+9
    )
);?>

Notice how the 4 sub-arrays were matched on year/month/day and then only the value was summed. I've seen other SO threads on this topic but can't find one where only the value is summed and not the year/month/day values too.

Thoughts?

2
  • 3
    It's much simpler if you just use DateTime objects. Commented Aug 27, 2012 at 12:43
  • @MrAzulay thanks can you show me/send a link for how the array matching/summing would look like using DateTime objects? I'll update my question to include this possible alternate format for $myArray. Commented Aug 27, 2012 at 12:45

2 Answers 2

4

It may be easiest to initially index your output array with a combination of the year/month/day:

Note: Your example array above has all its month keys with a trailing space. I'm just using month here with no trailing space.

// Initialize output array...
$out = array();

// Looping over each input array item
foreach ($myArray as $elem) {
  // Initialize a new element in the output keyed as yyyy-mm-dd if it doesn't already exist
  if (!isset($out[$elem['year'] . "-" . $elem['month '] . "-" . $elem['day']])) {
    $out[$elem['year'] . "-" . $elem['month '] . "-" . $elem['day']] = array(
      // Set the date keys...
      'year' => $elem['year'],
      'month' => $elem['month '],
      'day' => $elem['day'],
      // With the current value...
      'value' => $elem['value']
    );
  }
  // If it already exists, just add the current value onto it...
  else {
     $out[$elem['year'] . "-" . $elem['month '] . "-" . $elem['day']]['value'] += $elem['value'];
  }
}

// Now your output array is keyed by date.  Use array_values() to strip off those keys if it matters:
$out = array_values($out);

Outputs (before calling array_values()):

array(2) {
  '2011-5-13' =>
  array(4) {
    'year' =>
    int(2011)
    'month' =>
    int(5)
    'day' =>
    int(13)
    'value' =>
    int(3)
  }
  '2011-5-14' =>
  array(4) {
    'year' =>
    int(2011)
    'month' =>
    int(5)
    'day' =>
    int(14)
    'value' =>
    int(14)
  }
}

Update:

To do the same thing with single-key dates (rather than 3-parts) it is easier without the concatenation:

$myArray=array(
      array(
            'date' => '2011-05-13',
            'value' => 2
        ),
    array(
            'date' => '2011-05-14',
            'value' => 5
        ),
        array(
            'date' => '2011-05-13',
            'value' => 7
        ),
    array(
            'date' => '2011-05-14',
            'value' => 3
        ),

);

   foreach ($myArray as $elem) {
      // Initialize a new element in the output if it doesn't already exist
      if (!isset($out[$elem['date']])) {
        $out[$elem['date'] = array(
          // Set the date keys...
          'date' => $elem['date'],
          // With the current value...
          'value' => $elem['value']
        );
      }
      else {
        $out[$elem['date']]['value'] += $elem['value'];
      }
    }
Sign up to request clarification or add additional context in comments.

7 Comments

-@Michael, thanks following @MrAzulay's suggestion i can reformat the date's like this yyyy-mm-dd if this makes it easier (the sub-array only contains 2 and not 4 key-value pairs).
@DainisAbols I fixed the double [[ bracket already. copy/paste error
I tested your code and got this Parse error: syntax error, unexpected '[', expecting ']' in C:\data\test.php on line 40. That's at $out[[$elem['year'] . "-" . $elem['month'] . "-" . $elem['day']] = array(
@timpeterson Then the same pattern works, just don't use all the complicated concatenation to build the array key. Just $out[$elem['date']]
@MichaelBerkowski ok i can't quite get it, look at this gist: gist.github.com/3488345. I'd like to keep the $myArray array structure but this code doesn't do it. There should be only 2 sub-arrays in the $out array.
|
2

Here's how I would do it. The result will be in $newArray with datetime objects as keys. If you just want it as an indexed array it should be pretty easy to do.

// Example array
$myArray = array(
    array(
    'date' => new DateTime('1993-08-11'),
    'value' => 3
    ),

    array(
    'date' => new DateTime('1993-08-11'),
    'value' => 5
    )
);

$newArray = array();

foreach($myArray as $element)
{
    $iterationValue = $element['value'];
    $iterationDate = $element['date'];
    $dateKey = $iterationDate->format('Y-m-d');

    if(array_key_exists($dateKey, $newArray))
    {
        // If we've already added this date to the new array, add the value
        $newArray[$dateKey]['value'] += $iterationValue;
    }
    else
    {
        // Otherwise create a new element with datetimeobject as key
        $newArray[$dateKey]['date'] = $iterationDate;
        $newArray[$dateKey]['value'] = $iterationValue;
    }
}

nl2br(print_r($newArray));

Actually ended up doing the pretty much the same thing as @MichaelBerkowski solution. Still, having DateTime objects is always more flexible when you wan't to do things with the dates later in your application.

Edit: Now tested it and fixed errors

3 Comments

-@MrAzulay, thanks for your solution, is format() not declared somewhere?
@timpeterson What do you mean exactly? format() is a method in datetime that converts the date to a string. My first intention was to use the object as the key but I forgot that's not possible in PHP. So I had to make it a string
oh sorry, missed the new DateTime('xxxx-xx-xx') declaration, thought it was just xxxx-xx-xx. thanks

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.