【问题标题】:Merge two lists and create a new dictionary合并两个列表并创建一个新字典
【发布时间】:2016-08-30 12:36:06
【问题描述】:

我找不到这样做的好方法。假设我有两个列表(这些列表包含具有给定属性的对象)。我需要创建一个具有合并属性的新字典/列表。

listA = [
  {
    "alpha": "some value",
    "time": "datetime",
  },
  ...
]

listB = [
  {
    "beta": "some val",
    "gamma": "some val",
    "time": "datetime"
  },
  ...
]

结果应该如下(应该根据“时间”属性合并)

result = {
  "datetime": {
    "alpha": "some value",
    "beta": "some val",
    "gamma": "some val"
  },
  ...
}

我如何以 python 方式做到这一点?

例如,

listA = [
  {
    "time": "Jan 1",
    "alpha": "one"
  },
  {
    "time": "Jan 3",
    "alpha": "three"
  }
]

listB = [
  {
    "beta": "one-one",
    "gamma": "one-two",
    "time": "Jan 1"
  },
  {
    "beta": "two-one",
    "gamma": "two-two",
    "time": "Jan 2"
  },
]

result = {
  "Jan 1": {
    "alpha": "one",
    "beta": "one-one",
    "gamma": "one-two",
  },
  "Jan 2": {
    "beta": "two-one",
    "gamma": "two-two",
  },
  "Jan 3": {
    "alpha": "three"
  }
}

【问题讨论】:

  • 目前做得如何,该实现的具体问题是什么(如果问题是它不存在,那么首先修复它... )
  • 我没有看到太多证据表明您试图自己解决这个问题。
  • 我已经尝试并获得了使用 for 循环的解决方案。但我想知道是否有更直观的方法
  • 我在我的答案中添加了另一种方法,即使用列表推导。我不确定这是否更直观。在我看来,对于复杂的嵌套循环,普通的“for 循环”更直观,因为生成的代码更具可读性。然而,对于单循环,我发现列表推导通常更清晰。

标签: python list dictionary


【解决方案1】:

使用列表推导

由于您正在寻找不使用 for 循环的替代方案,因此这里是使用 list comprehensions 的实现,这会产生两个衬里。我不确定这是否比 for 循环更直观:

output = {}
[output.setdefault(item["time"],{}).update({key: value}) 
 for key, value in item.items()     
 if key != "time" 
 for item in (listA + listB)]

对我来说,这只是 for 循环的一种更复杂的方式...... setdefault 的文档。

使用经典的 for 循环

使用您的示例中给出的listAlistB

combined = listA + listB

merged = {}
for item in combined:
    time = item["time"]
    # setdefault only acts if the key is not found, initiate a dict then
    merged.setdefault(time, {})
    for key, value in item.items():
        if key != "time":
            merged[time].update({key: value})

print merged

输出:

{'Jan 2': {'beta': 'two-one', 'gamma': 'two-two'}, 'Jan 3': {'alpha': 'three'}, 'Jan 1': {'alpha': 'one', 'beta': 'one-one', 'gamma': 'one-two'}}

【讨论】:

    【解决方案2】:

    另一个答案,这可能更简洁,因为它避免了有利于 dict 方法的条件测试,并且只使用了一级缩进:

    d={}
    
    for e in listA:
        t = e["time"]
        d.setdefault(t, {}).update(**e)
    
    for e in listB:
        t = e["time"]
        d.setdefault(t, {}).update(**e)
    
    # get rid of "time" keys, if important to do so
    
    for e in d.values():
        del e["time"]
    

    如果t 键在d 中尚不存在,d.setdefault(t, {}) 创建一个空字典d[t],并返回d[t]。然后.update(**e) 更新返回的 dict 以包含 e 中的所有键和值(如果存在则替换当前值,这可能是错误或功能 - 该示例没有任何重叠或说明如果有应该发生什么重叠)

    【讨论】:

      【解决方案3】:

      这段代码可能是一个好的开始:

      listA = [
        {
          "time": "Jan 1",
          "alpha": "one"
        },
        {
          "time": "Jan 3",
          "alpha": "three"
        }
      ]
      
      listB = [
        {
          "beta": "one-one",
          "gamma": "one-two",
          "time": "Jan 1"
        },
        {
          "beta": "two-one",
          "gamma": "two-two",
          "time": "Jan 2"
        },
      ]
      result = {}
      
      # We consider every element of A and B one by one
      for elem in listA + listB:
          key = elem["time"]
      
          # If that is the first time we encounter that key, we create a new empty dict in result
          if not result.get(key, None):
              result[key] = {}
      
          # We copy the content of the elem in listA or listB into the right dictionnary in result.
          for dictKey in elem.keys():
      
              # We don't want to copy the time
              if dictKey == "time":
                  continue
              result[key][dictKey] = elem[dictKey]
      print(result)
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-11-02
        • 1970-01-01
        • 2016-01-02
        • 1970-01-01
        相关资源
        最近更新 更多