【问题标题】:Iterate over list of values dictionary迭代值字典列表
【发布时间】:2015-06-24 05:55:54
【问题描述】:

我有这样的字典

data = {
    'a': [95, 93, 90],
    'b': [643, 611, 610]
}

我想遍历字典并从每个项目的值列表中获取键和值,就像这样

{'a': 95, 'b': 643}
{'a': 93, 'b': 611}
{'a': 90, 'b': 610}

我已经实现了这个逻辑并且它工作正常,但是当我看到在进程中创建的temp_dict 时,我看到了很多中间不必要的循环。最终结果效果很好,但我认为它可以改进很多。

import timeit

data = {
    'a': [95, 93, 90],
    'b': [643, 611, 610]
}


def calculate(**kwargs):
    temp_dict = {}
    index = 0
    len_values = list(kwargs.values())[0]

    while index < len(len_values):
        for k, v in kwargs.items():
            temp_dict[k] = v[index]
        index += 1
        yield temp_dict


start_time = timeit.default_timer()
for k in (calculate(**data)):
    print(k)
print(timeit.default_timer() - start_time)

如何更有效地做到这一点?

【问题讨论】:

  • 既然你有一个工作代码,我认为你应该把它发布在代码审查部分。

标签: python dictionary


【解决方案1】:

试试这样的 -

>>> data = {
...     'a': [95, 93, 90],
...     'b': [643, 611, 610]
... }
>>> lst = list(data.items())
>>> lst1 = list(zip(*[i[1] for i in lst]))
>>> lst1
[(95, 643), (93, 611), (90, 610)]
>>> newlist = []
>>> for aval, bval in lst1:
...     newlist.append({lst[0][0]:aval , lst[1][0]:bval})
...
>>> newlist
[{'a': 95, 'b': 643}, {'a': 93, 'b': 611}, {'a': 90, 'b': 610}]

当使用 * 作为参数将列表传递给函数时,它会将列表分解为单独的元素并将其传递给函数。示例 - 如果我们传递 [[1,2],[3,4]],它将作为两个不同的参数传递 - [1,2][3,4] - 检查此 here(部分 - * 在函数调用中)

举例说明 -

>>> lst = [[1,2,3],[4,5,6],[7,8,9]]
>>> def func(a, b, c):
...     print(a)
...     print(b)
...     print(c)
...
>>> func(*lst)
[1, 2, 3]
[4, 5, 6]
[7, 8, 9]

zip - 此函数返回一个元组列表,其中第 i 个元组包含来自每个参数序列或可迭代对象的第 i 个元素。


更具可扩展性的模型 -

>>> lst = list(data.items())
>>> lst
[('a', [95, 93, 90]), ('b', [643, 611, 610])]
>>> lst1 = list(zip(*[i[1] for i in lst]))
>>> lst1
[(95, 643), (93, 611), (90, 610)]
>>> newlist = []
>>> for x in lst1:
...     d = {}
...     for i,y in enumerate(lst):
...             d[y[0]] = x[i]
...     newlist.append(d)
...
>>> newlist
[{'a': 95, 'b': 643}, {'a': 93, 'b': 611}, {'a': 90, 'b': 610}]

【讨论】:

  • 嘿,你有没有链接到解释*list(zip(*data.values())) 中的sifnficance 的文章
  • 如果 dict 在编码时不知道怎么办?
  • 我会更新一些可扩展模型的答案
  • 你可以通过使用更多的zip来消除使用enumeratei[1]y[0]x[i]之类的东西的尴尬。它会更漂亮:)
  • 为什么enumeratei[1] 这么别扭?我怎样才能改用zip?你能帮我理解吗
【解决方案2】:

用列表理解来做这件事很有趣。

>>> data = {
'a': [95, 93, 90],
'b': [643, 611, 610]
}
>>> [dict(zip(data, x)) for x in zip(*data.values())] 
[{'a': 95, 'b': 643}, {'a': 93, 'b': 611}, {'a': 90, 'b': 610}]

或者更传统(不那么有趣)的方式

>>> result = []
>>> for tuple_ in zip(*data.values()):
...     d = {}
...     for key, val in zip(data, tuple_):
...         d[key] = val
...     result.append(d)
>>> print result
[{'a': 95, 'b': 643}, {'a': 93, 'b': 611}, {'a': 90, 'b': 610}]

对于每个 cmets,这是一种不依赖“非保证”行为的方法,例如 data.keys() 和 data.values() 的相同顺序。

列表理解

>>> keys, values = zip(*data.items())
>>> [dict(zip(keys, tuple_)) for tuple_ in zip(*values)]
[{'a': 95, 'b': 643}, {'a': 93, 'b': 611}, {'a': 90, 'b': 610}]

和传统的for循环

>>> result = []
>>> keys, values = zip(*data.items())
>>> for tuple_ in zip(*values):
...     d = {}
...     for key, val in zip(keys, tuple_):
...         d[key] = val
...     result.append(d)
>>> print result
[{'a': 95, 'b': 643}, {'a': 93, 'b': 611}, {'a': 90, 'b': 610}]

【讨论】:

  • 你的回答很漂亮。它可以进一步扩展为使用生成器表达式,例如yield from (dict(zip(kwargs, x)) for x in zip(*kwargs.values()))
  • 是的,很难在写作的乐趣和阅读的可接受性之间找到平衡。
  • 字典没有秩序感,你确定你的解决方案会一直有效吗?
  • 我的意思是即使您在同一行中多次访问data 字典,它们也可以以不同的顺序给出结果(理论上)
  • @AnandSKumar 我们正在访问字典中列表的元素。所以基本上我们正在获取列表元素列表本质上是有序的,所以我认为它是正确的。如果我错了,请纠正我
【解决方案3】:

如果在编码时不知道用作键的数字和实际文字,这里有一个想法:

您可以生成一系列类似 dict 的对象。每个实例都会暴露值列表中的第 i 个值。你可以阅读emulating python container types

【讨论】:

    【解决方案4】:

    与此类似(但将 print 替换为 yield):

    keys = []
    values = []
    for k, v in data.iteritems():
        keys.append(k)
        values.append(v)
    for vals in zip(*values):
        print dict(zip(keys, vals))
    

    第二个for循环中的zip(*values)或多或少transposesvalues中的列表列表。更简洁的写法:

    keys = list(data)
    for vals in zip(*data.values()):
        print dict(zip(keys, vals))
    

    在这两种情况下,结果都是:

    {'a': 95, 'b': 643}
    {'a': 93, 'b': 611}
    {'a': 90, 'b': 610}
    

    【讨论】:

      【解决方案5】:

      这是一种方法:

      data = {
          'a': [95, 93, 90],
          'b': [643, 611, 610]
      }
      
      x = data.values()
      d1 = {'a':x[0][0], 'b':x[1][0]}
      d2 = {'a':x[0][1], 'b':x[1][1]}
      d3 = {'a':x[0][2], 'b':x[1][2]}
      

      输出:

      {'a': 95, 'b': 643}
      {'a': 93, 'b': 611}
      {'a': 90, 'b': 610}
      

      【讨论】:

      • 编码时不知道字典。
      • @ajkumar25 你是什么意思不知道?
      • dict 的键值会有所不同。字典不是恒定的,
      • @ajkumar25 如果您想从此字典中获取此输出,则此代码有效
      • @JoeR 不错的解决方案。我认为他的意思是可能有更多的键(例如,除了“a”和“b”之外的“c”),因此代码不能直接引用键值,否则它不适用于所有可能的输入。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2015-09-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-07-28
      • 2013-07-01
      相关资源
      最近更新 更多