【问题标题】:How to efficiently combine two (or more) associative arrays with common keys如何有效地将两个(或多个)关联数组与公共键组合起来
【发布时间】:2023-04-09 17:37:01
【问题描述】:

更一般地说,假设我们有两个不同长度的列表,但有一个共同的属性:

list1: {
         {"orderID":1234, "FirstName":"shaheeb", "LastName":"roshan"},
         {"orderID":9183, "FirstName":"robert", "LastName":"gibbons"},
         {"orderID":2321, "FirstName":"chester"},
       }
list2: {
         {"orderID":1234, "cell":"555-555-5555", "email":"roshan@fake.com"},
         {"orderID":2321, "email":"chester@fake.com"},
       }

我想把这些组合成:

list3: {
         {"orderID":1234, "FirstName":"shaheeb", "LastName":"roshan", "cell":"555-555-5555", "email":"roshan@fake.com"},
         {"orderID":9183, "FirstName":"robert", "LastName":"gibbons"},
         {"orderID":2321, "FirstName":"chester", "email":"chester@fake.com"},
       }

我主要是一名 PHP 开发人员,我想出了以下内容:

function mergeArrays($a1, $a2) {
    $larger = (count($a1) > count($a2)) ? $a1 : $a2;
    $smaller = ($larger == $a1) ? $a2 : $a1;
    $combinedArray = array();
    foreach ($larger AS $key=>$largerSet) {
        $combinedRow = array();
        if (isset ($smaller[$key]) ) {
            $combinedRow = $largerSet + $smaller[$key];
            $combinedArray[$key] = $combinedRow;
        }else {
            $combinedArray[$key] = $largerSet;
        }
    }
    return ($combinedArray);
}

如果使用以下测试:

$array1 = array("12345"=>array("OrderID"=>12345, "Apt"=>"blue"));
$array2 = array(
                "12345"=>array("OrderID"=>12345, "AnotherCol"=>"Goons", "furtherColumns"=>"More Data"),
                "13433"=>array("OrderID"=>32544, "Yellow"=>"Submarine")
            );

mergeArrays($array1, $array2) 输出以下内容:

array(2) {
  [12345]=>
  array(4) {
    ["OrderID"]=>
    int(12345)
    ["AnotherCol"]=>
    string(5) "Goons"
    ["furtherColumns"]=>
    string(9) "More Data"
    ["Apt"]=>
    string(4) "blue"
  }
  [13433]=>
  array(2) {
    ["OrderID"]=>
    int(32544)
    ["Yellow"]=>
    string(9) "Submarine"
  }
}

但我只是觉得这不是最优雅的解决方案。例如,我应该能够组合 n 个数组。不太确定我将如何做到这一点。另外,只要看看那段代码,我就相当肯定有更有效的方法可以实现这一要求。

作为一个学习点,我很好奇python专家是否会借此机会向我们展示PHP人员:)。就此而言,我很好奇 Excel/VBA 是否可以处理这个问题。这就是我开始尝试解决这个问题的地方,我的想法是“excel 肯定可以处理列表!”。

我完全意识到这个问题围绕 SO 有很多变体。我已经看过其中的几个,但仍然觉得我应该在这里试用我的版本。

非常感谢您的想法。

谢谢!

SR

【问题讨论】:

  • 您在寻找 PHP 解决方案还是 Python 解决方案?我认为是 Python,对吧?
  • 要么 1)使语言不可知(例如“组合理论”,这很无聊),要么 2)只留下一个语言标签 :-) 对于更大/更小的东西,算法可能太复杂了.真正发生的是对某个属性(或一组属性)的“连接”,这是一个由两部分组成的操作(检测 - 找到可连接的值 - 并合并)。

标签: php python arrays merge


【解决方案1】:

对于 Python 中的通用解决方案,对于任意数量的列表:

orders = defaultdict(dict)
for order_list in order_lists:
    for order in order_list:
        orders[order['orderID']].update(order)

在线查看:ideone

【讨论】:

  • 请注意,这将适用于 Python 2.7(我相信)或更高版本 - +1 以获得 非常 不错的答案!
  • 我在对问题的回答中编写了一个更通用的形式。
【解决方案2】:

嗯,你总是可以用 array_merge_recursive 替换你的函数。

【讨论】:

    【解决方案3】:

    一种通用的解决方案,可以合并任意数量的 dicts(或一个 dicts 列表 - 如果您有多个列表,只需在调用函数之前将它们加在一起):

    from collections import defaultdict
    
    def merge_dicts_by_key(key, *dicts):
        return reduce(lambda acc,val: acc[val[key]].update(val) or acc,
                      dicts,
                      defaultdict(dict))
    

    这样调用:

    merge_dicts_by_key('orderId', dict1, dict2, dict3)
    

    或者,如果你有字典列表:

    merge_dicts_by_key('orderId', *list_of_dicts)
    merge_dicts_by_key('orderId', *(list1 + list2))
    

    【讨论】:

    • 你的lambdadicts被交换了;但我把它们放在正确的位置,这仍然对我不起作用。我不知道为什么。
    • 哎呀。修复了那里的订单。你是如何调用它的?
    • 发现问题。忘记了 x.update(y) 在完成后实际上并没有返回 x ,并且 reduce 期望函数返回结果而不是就地修改累加器。将 or acc 添加到 lambda 的末尾修复它,因为 update() 返回 None ,因此 or 将始终评估为新更新的 acc
    • 啊,太好了。 +1 然后是一个简洁和通用的解决方案。 (实际上我在测试之前赞成它:))
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-09-25
    • 2019-11-11
    • 1970-01-01
    • 2020-10-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多