【问题标题】:Merging two arrays with combining duplicates by one of fields合并两个数组并通过其中一个字段组合重复项
【发布时间】:2013-11-08 06:29:48
【问题描述】:

我在按特定场景合并数组时遇到了麻烦。搜索类似的案例在这里没有结果。要清楚地了解我的要求是什么,请看下一个示例:

第一个数组:

Array
(
    [0] => stdClass
        (
            [call_date] => 2013-10-22 00:00:00
            [first_amount] => 10
        )

    [1] => stdClass
        (
            [call_date] => 2013-10-23 00:00:00
            [first_amount] => 20
        )
)

第二个数组:

Array
(
    [0] => stdClass
        (
            [call_date] => 2013-10-22 00:00:00
            [second_amount] => 30
        )

    [1] => stdClass
        (
            [call_date] => 2013-10-24 00:00:00
            [second_amount] => 40
        )
)

我在输出中需要什么:

Array
(
    [0] => stdClass
        (
            [call_date] => 2013-10-22 00:00:00
            [first_amount] => 10
            [second_amount] => 30
        )

    [1] => stdClass
        (
            [call_date] => 2013-10-23 00:00:00
            [first_amount] => 20
        )

    [2] => stdClass
        (
            [call_date] => 2013-10-24 00:00:00
            [second_amount] => 40
        )
)

如您所见,合并按 call_date 进行。合并第一个和第二个数组中日期为 2013-10-22 00:00:00 的项目,添加第二个数组中日期为 2013-10-24 00:00:00 的项目。

尝试了很多array_merge、array_udiff、array_merge_recursive、array_map的组合,但没有任何帮助:(。

感谢您解决这个问题!

【问题讨论】:

  • 每个都有一个测试条件? php.net/manual/en/control-structures.foreach.php 。所有这些功能都只是 foreach。
  • 数组函数在这里不会特别有用——因为数组中没有数组,而是对象。因此,您必须将属性附加到现有对象或创建一个新对象,无论您的第一个数组中是否已经存在具有 call_date 的对象。
  • 只是一个foreach,使用call_date作为新数组的键,如果一个项目不存在,添加,如果存在,添加*_amount列(或者只是@987654328 @ (你说的是合并 object 这里。
  • @Remi,感谢您的回答。那么使用 foreach 的最佳方式是什么?我应该使用嵌套的 foreach-s 吗?
  • 不,对于要添加到其中的每个数组,只需连续 1 个 foreach。(所以 foreach($array1 as $item){..}foreach($array2 as $item){..} 等)

标签: php arrays merge stdclass


【解决方案1】:
$result = $first;
$amounts = array('first_amount','second_amount');
foreach ($first as $fKey => $f) {
    foreach ($second as $sKey => $s) {
        if ($f['call_date'] == $s['call_date']) {
            foreach ($amounts as $amount) {
                if (!isset($f[$amount]) && isset($s[$amount]))
                    $result[$fKey][$amount] = $s[$amount];
            }
            unset($second[$sKey]);
            break;
        }
    }
}
$result = array_merge($result, $second);

如果您有更多键添加到数量数组,如果您想替换现有键,请从条件中删除 !isset($f[$amount]) &&,并且您有多个相等的 call_date 也删除 break;。

【讨论】:

    【解决方案2】:
    $arr1 = array(  array(  'call_date'    => '2013-10-22 00:00:00',
                            'first_amount' => 10),
                    array(  'call_date'    => '2013-10-23 00:00:00',
                            'first_amount' => 20));
    
    $arr2 = array(  array(  'call_date'     => '2013-10-22 00:00:00',
                            'second_amount' => 30),
                    array(  'call_date'     => '2013-10-24 00:00:00',
                            'second_amount' => 40));
    
    $arr_merged = array_merge($arr1, $arr2);
    
    $arr_result = array();
    foreach ($arr_merged as $arr) {
    
        if ( ! isset($arr_result[$arr['call_date']]))
            $arr_result[$arr['call_date']] = array();
    
        $arr_result[$arr['call_date']] += $arr;
    
    }
    
    $arr_result = array_values($arr_result);
    
    1. 定义相关数组,如$arr1 和$arr2
    2. array_merge() them
    3. 在'call_date' 上使用union logic 创建一个新数组
    4. 通过array_values()删除作为键的日期

    【讨论】:

    • 没用。对于大数组有错误:Notice: Undefined index: 2013-06-26 03:00:00 ...Fatal error: Unsupported operand types ...
    • 立即尝试。可能需要先将值定义为array。
    • 是的,现在正在工作。比@ziollek 的解决方案慢一点(25-30 毫秒到 40-45 毫秒),但也可以。这是替代解决方案!谢谢!
    【解决方案3】:

    简单场景:

    1. 更改数组键
    2. 合并递归
    3. 将合并的元素映射回对象 (stdClass)

    例子:

    //change key
    $workFirstArray = array_combine(
        array_map(function($object) { return $object->call_date;}, $firstArray), $firstArray
    );
    $workSecondArray = array_combine(
        array_map(function($object) { return $object->call_date;}, $secondArray), $secondArray
    );
    
    //map merged elements back to StdClass
    $result = array_map(function($element) {
            if(is_array($element)) {
                $element['call_date'] = end($element['call_date']);
                $element=(object)$element;
            }
            return $element;
        },
        array_merge_recursive($workFirstArray, $workSecondArray)
    );
    

    输出:

    Array
    (
        [0] => stdClass Object
            (
                [call_date] => 2013-10-22 00:00:00
                [first_amount] => 10
                [second_amount] => 40
            )
    
        [1] => stdClass Object
            (
                [call_date] => 2013-10-23 00:00:00
                [second_amount] => 30
            )
    
        [2] => stdClass Object
            (
                [call_date] => 2013-10-24 00:00:00
                [second_amount] => 40
            )
    
    )
    

    【讨论】:

    • 哇,这很有效,而且速度非常快!非常感谢!只添加了一件事来完成您的解决方案:$result = array_values($result);
    【解决方案4】:
    $result = array();
    $result = $firstArray;
    for ($i=0; $i < count($firstArray); $i++){
        for ($j=0; $j < count($secondArray); $j++){
            if ($firstArray[$i]['call_date'] == $secondArray[$j]['call_date']){
                $result[$i]['second_amount'] = $secondArray[$j]['second_amount'];
                break;
            }
        }
        if ($j == count($secondArray))
            $result[] = $secondArray[$j-1];
    }
    var_dump($result);
    

    【讨论】:

    • 您的解决方案需要固定索引(如 second_amount),但它必须独立于它们。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-03-22
    • 2019-02-22
    • 2017-06-22
    • 1970-01-01
    • 2011-08-30
    • 2021-12-27
    • 1970-01-01
    相关资源
    最近更新 更多