PHP数组:按匹配日期求和值

4
我是一位有用的助手,可以为您翻译文本。
我正在尝试找出如何对多维数组中具有相似日期的某些值进行求和。
这是我的数组:
<?$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
    )
);?>

以下是我希望输出的格式:

以下是我的期望输出结果:

<?$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
    )
);?>

请注意,4个子数组是根据年/月/日进行匹配的,然后只对value求和。我看过其他关于此主题的SO线程,但没有找到只对value进行求和而不对year/month/day值进行求和的线程。
你有什么想法?

3
如果您只使用DateTime对象,那么会更加简单。 - Jonathan
@MrAzulay谢谢,您能给我展示一下/发送一个有关如何使用DateTime对象的数组匹配/求和的链接吗? 我会更新我的问题以包含此可能的$myArray替代格式。 - tim peterson
2个回答

4

最好的方法可能是用年/月/日的组合来初始化您的输出数组索引:

注意:您上面的示例数组所有 month 键都有尾随空格。我这里只使用 month不带尾随空格。

// 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);

调用 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)
  }
}

更新:

如果只涉及单键日期(而不是三部分),那么不需要连接,这样做更容易:

$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'];
      }
    }

@Michael,感谢您遵循@MrAzulay的建议,如果这样做可以简化操作的话,我可以将日期重新格式化为“yyyy-mm-dd”(子数组仅包含2个而不是4个键值对)。 - tim peterson
1
@DainisAbols,我已经修复了双重的[[括号。这是复制/粘贴错误。 - Michael Berkowski
1
我测试了你的代码,得到了这个错误信息:Parse error: syntax error, unexpected '[', expecting ']' in C:\data\test.php on line 40。这是在 $out[[$elem['year'] . "-" . $elem['month'] . "-" . $elem['day']] = array( 这一行发生的。 - Peon
@timpeterson 然后同样的模式适用,只是不要使用所有复杂的连接来构建数组键。只需使用 $out[$elem['date']] 即可。 - Michael Berkowski
@MichaelBerkowski 好的,我还不太明白,请看这个代码片段:https://gist.github.com/3488345。我想保留 $myArray 数组结构,但是这段代码做不到。$out 数组中应该只有 2 个子数组。 - tim peterson
显示剩余2条评论

2
这是我会做的方式。结果将在$newArray中,其中datetime对象为键。如果您只希望它作为索引数组,那么这应该很容易实现。
// 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));

实际上,最终做的事情与 @MichaelBerkowski 的解决方案几乎相同。不过,如果你以后想在应用程序中对日期进行操作,使用 DateTime 对象始终更加灵活。

编辑:现在已经测试并修复了错误。


@MrAzulay,感谢您的解决方案,format()没有在任何地方声明吗? - tim peterson
1
@timpeterson 你的意思是什么?format() 是 datetime 中将日期转换为字符串的方法。我的第一个想法是使用对象作为键,但我忘记了在 PHP 中这是不可能的。所以我不得不将其转换为字符串。 - Jonathan
哦,抱歉,我漏掉了 new DateTime('xxxx-xx-xx') 的声明,以为只是 xxxx-xx-xx。谢谢。 - tim peterson

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接