【问题标题】:Combinations of two non-consecutive items两个不连续项目的组合
【发布时间】:2016-11-05 13:16:00
【问题描述】:

给定一个列表,如何获得两个非连续项目之间的所有组合?

例如,对于输入[1, 2, 3, 4, 5],我怎样才能得到输出[(1,3), (1,4), (1,5), (2,4), (2,5), (3,5)]

我对@9​​87654324@、(2,3)(3,4)(4,5) 不感兴趣,因为它们在列表中是连续的(即彼此相邻),但我感兴趣的其他所有内容。

在 Python 中最惯用的方法是什么?

【问题讨论】:

  • consecutive 表示在列表中彼此相邻或在自然数中紧随其后的数字?
  • @thefourtheye 感谢您的帮助。连续我的意思是在列表中彼此相邻。该列表甚至可能不是数字,我只是认为它更容易可视化。我会在问题中添加一些内容以澄清它。
  • 查看itertools 并选择您需要的功能:docs.python.org/2/library/itertools.html 您可能需要过滤它们。

标签: python list combinations


【解决方案1】:

一个简单的列表理解:

>>> lst = [1, 2, 3, 4, 5]
>>> [(a, b) for i, a in enumerate(lst) for b in lst[i+2:]]
[(1, 3), (1, 4), (1, 5), (2, 4), (2, 5), (3, 5)]

【讨论】:

  • 一个小小的优化:enumerate(lst[:-2]).
  • @ivan_pozdeev 嗯,我不喜欢它。而且我不相信这是一种优化。我认为它更糟。是的,你阻止了我的最后两次迭代,但它们的 lst[i+2:] 是空的,所以它几乎没有节省任何东西。而且它是以几乎整个列表的另一个副本为代价的,这也需要一些时间,并且会一直占用内存。
  • 它将对k≈n 发挥更大的作用 - 例如如果这些是numpy 数组而不是在切片时不复制的列表。
  • 无论如何,这里是硬数字(你的/我的,1000 的列表):k=2 - 175ms/178msk=900 - 1.96ms/ 1.47ms;对于 NumPy 数组,258ms/265ms5.6ms/2.8ms 对应。
  • @ivan_pozdeev 谢谢,我总是喜欢硬数字:-)。我得到了相似的比率,像timeit('[(a, b) for i, a in enumerate(lst[:-899]) for b in lst[i+900:]]', 'lst = range(1000)', number=10000) 一样测试它(我也想看看硬数字是如何得到的)。这是您对“k”的概括吗?我一点也不惊讶你的方式在大“k”下更好,但这不是这里的问题,所以我仍然会坚持我原来的方式。
【解决方案2】:

这是一种相当“惯用”的方式,不使用任何模块,它比其他一些实现更有效,因为每次循环都被使用——没有被拒绝的可能性。

r = [1, 2, 3, 4, 5]
c = [(r[i], r[j]) for i in range(len(r)-2) for j in range(i+2, len(r))]
print(c)

这给了

[(1, 3), (1, 4), (1, 5), (2, 4), (2, 5), (3, 5)]

这不是完全惯用的,因为它循环索引而不是值,但是您对列表中位置而不是值的限制使得这相当必要。如果您想要生成器而不是列表,请将外括号替换为圆括号。

【讨论】:

  • 这基本上是@StefanPochman's answer 的优化(以可读性为代价),它避免了复制列表。您可以使用xrange 获得更多加速。由于ranges 比 C 循环慢得多,它实际上比@StefanPochman 的回答270ms vs 174ms 在我的机器上的大小为 1000 的列表。
【解决方案3】:

如果您对列表中不连续数字的组合感兴趣:

from itertools import combinations

lst = [1, 2, 3, 4, 5]
list(filter(lambda x: lst.index(x[1]) - lst.index(x[0]) > 1, combinations(lst,2)))

[(1, 3), (1, 4), (1, 5), (2, 4), (2, 5), (3, 5)]

这会比较给定组合中两个数字的索引,并确保它们的索引之差大于 1。

希望对你有帮助。

【讨论】:

    【解决方案4】:

    这是避免连续元素的 r 长度组合的通用解决方案。它获取所有索引combinations 以获得适当较短的列表,然后展开每个组合的索引。例如对于 r=3,任何组合 (x,y,z) 都会变成使用的索引 x+0、y+1、z+2。

    from itertools import combinations
    
    def non_consecutive_combinations(lst, r):
        return [tuple(lst[j+i] for i, j in enumerate(combi))
                for combi in combinations(range(len(lst)-r+1), r)]
    

    r=2 的演示:

    >>> non_consecutive_combinations([1, 2, 3, 4, 5], 2)
    [(1, 3), (1, 4), (1, 5), (2, 4), (2, 5), (3, 5)]
    

    r=3 的演示:

    >>> non_consecutive_combinations([1, 2, 3, 4, 5, 6, 7], 3)
    [(1, 3, 5), (1, 3, 6), (1, 3, 7), (1, 4, 6), (1, 4, 7), (1, 5, 7), (2, 4, 6), (2, 4, 7), (2, 5, 7), (3, 5, 7)]
    

    仅适用于配对的简化版本:

    >>> [(lst[i], lst[j+1]) for i, j in combinations(range(len(lst)-1), 2)]
    [(1, 3), (1, 4), (1, 5), (2, 4), (2, 5), (3, 5)]
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-04-17
      • 1970-01-01
      • 2021-11-07
      • 2020-08-15
      • 2018-04-22
      • 1970-01-01
      • 2020-10-29
      • 1970-01-01
      相关资源
      最近更新 更多