【问题标题】:Split list by criterion [duplicate]按标准拆分列表[重复]
【发布时间】:2017-07-28 10:16:58
【问题描述】:

假设我有一个数字列表,我想将此列表拆分为两个子列表:一个用于奇数,另一个用于偶数。

evens, odds = [], []
for e in numbers:
    if e % 2 == 0:
        evens.append(e)
    else:
        odds.append(e)

我想知道在保持相同复杂性顺序的同时,是否存在针对此问题的单行代码。

我尝试使用itertools.groupby,但需要先对列表进行排序,因此我将获得O(2n) 而不是O(n)

def is_even(n):
    return n % 2 == 0

lst = sorted(lst, key=is_even)
grouper = itertools.groupby(lst, key=is_even)
lst1, lst2 = [list(v) for k, v in grouper]

【问题讨论】:

  • 附带说明,O(2n)O(n) 具有相同的幅度,并且大部分时间可以被视为相等。
  • O(2n) 和 O(n) 一样,只是说...
  • @DeepSpace 是的,我知道,但它仍然慢了一倍,这让我很困扰,我宁愿尽可能高效地进行操作
  • 顺便说一下,虽然我们正在这样做,但您的groupby 解决方案不是O(2n)。由于sorted 使用快速排序,您的第二个解决方案的复杂性(平均)为O(nlogn + n)
  • @DeepSpace 真的,我真的没有停下来思考正在使用什么排序算法,我的意思是它增加了第一个循环没有引入的额外复杂性

标签: python list


【解决方案1】:

在追加之前使用三元运算符怎么样:

evens, odds = [], []
for e in numbers:
    (odds if e % 2 else evens).append(e)

当然,您可以在列表推导中执行此操作,但使用推导来处理它的副作用并不是 Pythonic,因为您创建了一个可能很大的不需要的 None 值列表。如果你想走这条路,你可以改用itertools consume recipe

【讨论】:

  • 不是最容易阅读的,但我认为这个答案最合适,因为它是 O(n)。
  • 您能否详细说明如何使用consume 回答这个问题?
  • @dabadaba 就像consume((odds if e % 2 else evens).append(e) for e in numbers)
  • @dabadaba 实际上,对于您的情况,您可以使用collections.deque(((odds if e % 2 else evens).append(e) for e in numbers), maxlen=0)
  • 这很不错!我会尽量记住那个食谱……
【解决方案2】:

可以滥用列表理解,但请不要在生产代码中这样做。

nums = range(6)
odds = []
evens = []
[odds.append(num) if num % 2 == 1 else evens.append(num) for num in nums]
print(odds, evens)
# [1, 3, 5] [2, 4]

【讨论】:

  • 这是使用列表理解的不好方式
  • @DeepSpace 是的,我在发帖前就看到了,但无论如何我都不推荐。
猜你喜欢
  • 2014-05-17
  • 2014-08-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-01-05
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多