【问题标题】:Inline version of a for loop with `.add` or `.append`带有 `.add` 或 `.append` 的 for 循环的内联版本
【发布时间】:2021-03-14 00:32:58
【问题描述】:

是否有一种干净的内联方式来定义具有.add 或.append 的for 循环?例如,考虑以下for 循环:

import collections

s = [('red', 1), ('blue', 2), ('red', 3), ('blue', 4), ('red', 1), ('blue', 4)]
d = collections.defaultdict(set)
for k, v in s:
  d[k].add(v)

我可以考虑像下面的代码那样内联写它,但它看起来并不干净:

_ = [d[k].add(v) for k, v in s]

有没有更好的方法,例如使用itertools.accumualte?类似的东西

d = ...

【问题讨论】:

  • 你想通过使其“内联”来实现什么?使用明确的for 循环很好。如果您经常这样做,请将其放入函数中(或使用库;在这种情况下,查找“multi dict”或“bag”)。
  • 我认为,你的代码很干净 :) 实际上,它很干净。
  • 我本人通常是 itertools 的忠实拥护者,甚至我也同意您拥有的代码可能是最简洁的方式。坚持这种本能,因为它很好,但我认为它不适用于这种情况。

标签: python python-3.x for-loop inline


【解决方案1】:

我仍然认为您的第一种方法比这个答案非常干净而且更好,但这是一个单线解决方案:

import itertools

...    

d = {k: set(v for _, v in g) for k, g in itertools.groupby(sorted(s), lambda x: x[0])}
print(d)

输出:

{'blue': {2, 4}, 'red': {1, 3}}

另一种方法(不是单行):

d = collections.defaultdict(set)

def change_dict(k, v):
    d[k].add(v)

list(itertools.starmap(change_dict, s)) # list is to call iterator
print(d)

输出:

defaultdict(<class 'set'>, {'red': {1, 3}, 'blue': {2, 4}})

【讨论】:

  • 这很好,但它需要排序,这对速度来说不是最佳的。
  • @user2725109 是的,不幸的是,它需要先排序。顺便说一句,刚刚添加了另一种方法。它不是一条线,但它可能会引导你到达某个地方。
【解决方案2】:

使用itertools.accumulate。可能效率不高,但可以解决问题。

d = itertools.accumulate(
    s,
    lambda d, kv: dict(d, **{kv[0]: d.get(kv[0], set()).union({kv[1]})}),
    initial=dict())
d = list(d)[-1]

【讨论】:

    猜你喜欢
    • 2015-03-14
    • 2013-10-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-08-12
    • 2020-12-22
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多