【问题标题】:Efficient way to either create a list, or append to it if one already exists?创建列表或附加到列表(如果已经存在)的有效方法?
【发布时间】:2018-01-30 06:59:33
【问题描述】:

我正在处理一大堆具有多对多相关性的元组,我想制作一个字典,其中 (a,b) 的每个 b 都有一个与 a b 对应的所有 a 的列表.在字典中的键 b 处测试一个列表似乎很尴尬,然后查找一个 a,如果它不存在则附加 a,每次都通过元组消化循环;但我还没有找到更好的方法。一个存在吗?还有其他更漂亮的方法吗?

【问题讨论】:

  • 更漂亮是指语法还是算法?

标签: python list


【解决方案1】:

请参阅the docs 了解setdefault() 方法:

setdefault(key[, default])
如果键是 在字典中,返回它的值。 如果不是,则插入值为 默认并返回默认值。默认 默认为无。

您可以将其用作单个调用,如果 b 存在则获取 b,或者如果 b 不存在则将 b 设置为空列表 - 无论哪种方式,都返回 b:

>>> key = 'b'
>>> val = 'a'
>>> print d
{}
>>> d.setdefault(key, []).append(val)
>>> print d
{'b': ['a']}
>>> d.setdefault(key, []).append('zee')
>>> print d
{'b': ['a', 'zee']}

将此与一个简单的“不在”检查结合起来,您已经在三行中完成了您所追求的:

>>> b = d.setdefault('b', [])
>>> if val not in b:
...   b.append(val)
... 
>>> print d
{'b': ['a', 'zee', 'c']}

【讨论】:

  • defaultdictsetdefault 好一点,前提是你有 Python 2.5 或更高版本。
  • 我坚持使用 2.34,所以这实际上是答案,对我来说——谢谢,詹姆斯!
  • 哦。 set() 很好,但直到 2.4 才内置。为什么你的 Python 这么老? :-(
  • defaultdict 还需要额外导入 collections
【解决方案2】:

假设您并没有真正受制于列表,defaultdictset 非常方便。

import collections
d = collections.defaultdict(set)
for a, b in mappings:
    d[b].add(a)

如果你真的想要列表而不是集合,你可以在后面加上一个

for k, v in d.iteritems():
    d[k] = list(v)

如果你真的想要一个dict而不是defaultdict,你可以说

d = dict(d)

不过,我真的看不出有什么理由。

【讨论】:

  • 啊,是的,这绕过了最初的无价值检查。谢谢!我学到了一些新东西。 :)
  • +1 for defaultdict,因为它确实是最 Pythonic 的解决方案。
  • 如果你想要列表而不是集合,你可以这样做: import collections d = collections.defaultdict(list) for a, b in mappings: d[b].append(a)
【解决方案3】:

使用 collections.defaultdict

your_dict = defaultdict(list)
for (a,b) in your_list:
    your_dict[b].append(a)

【讨论】:

  • OP 的“如果不存在则附加 a”让我认为原始列表可能包含应过滤掉的重复项,这就是我使用 set 而不是 list 的原因。
  • @ephemient: 啊,解绑了。如果“它”仅仅意味着列表,那么defaultict(list) 是对的。如果“它”表示集合中的每个项目,那么defaultdict(set) 是正确的。而当“它”下雨时,“它”与什么有关?
  • 如果 OP 有他们的(大概)工作的、丑陋的代码而不是用英语模棱两可的描述,那就太好了 :-)
  • @ephemient:这就是我投票赞成你的答案的原因......我认为这可能会更好,因为set 可能比list 更有意义。
【解决方案4】:

你可以排序你的元组 O(n log n) 然后创建你的字典 O(n)

或者更简单的 O(n),但是在有很多元组的情况下可能会给内存带来沉重的负担:

your_dict = {}
for (a,b) in your_list:
    if b in your_dict:
        your_dict[b].append(a)
    else:
        your_dict[b]=[a]

嗯,和你描述的差不多。这有什么尴尬的?

您也可以考虑使用 sql 数据库来完成这项繁琐的工作。

【讨论】:

  • 顺便说一句,更简单的方法是 O(n),所以它比你的 tuples 方法更可取。
【解决方案5】:

而不是使用if,AFAIK 更pythonic 使用try 块代替。

your_list=[('a',1),('a',3),('b',1),('f',1),('a',2),('z',1)]

your_dict={}
for (a,b) in your_list:
    try:
        your_dict[b].append(a)
    except KeyError:
        your_dict[b]=[a]

print your_dict

【讨论】:

    【解决方案6】:

    我不确定你将如何摆脱键测试,但是一旦它们的键/值对被初始化就很容易了:)

    d = {}
    if 'b' not in d:
      d['b'] = set()
    d['b'].add('a')
    

    该集合将确保集合中只有 1 个“a”。您需要进行初始的“b”检查以确保键/值存在。

    【讨论】:

    • 好奇为什么-1?这是错误的吗?回答错了我会删除。
    【解决方案7】:

    字典get 方法? 如果some_key 在字典中,则返回my_dict[some_key] 的值,否则返回一些默认值(以下示例中的[]):

    my_dict[some_key] = my_dict.get(some_key, []).append(something_else)
    

    【讨论】:

    • 这是不正确的。 append 不返回列表。它变成my_dict[some_key] = None
    【解决方案8】:

    还有另一种相当有效(尽管可能不如集合有效)且简单的方法。它在实践中类似于defaultdict,但不需要额外的导入。 假设您有一个带有空(无)键的 dict,这意味着您还在某处创建了 dict 键。您可以使用dict.fromkeys 方法来做到这一点,并且此方法还允许为所有键设置默认值。

    keylist = ['key1', 'key2']
    result = dict.fromkeys(keylist, [])
    

    result 将是: {'key1':[],'key2':[]}

    然后你可以做你的循环并直接使用result['key1'].append(..)

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2022-01-06
      • 2011-11-21
      • 2021-11-14
      • 1970-01-01
      • 2020-09-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多