【问题标题】:Intersection of two lists including duplicates?两个列表的交集,包括重复项?
【发布时间】:2016-06-05 17:58:58
【问题描述】:
>>> a = [1,1,1,2,3,4,4]
>>> b = [1,1,2,3,3,3,4]

[1,1,2,3,4]

请注意,这不是同一个问题: Python intersection of two lists keeping duplicates 因为即使列表 a 中有三个 1,列表 b 中也只有两个,所以结果应该只有两个。

【问题讨论】:

  • 怎么不是重复的?你了解交集的定义吗?这个问题的问题是第二个列表的重复项被set()删除了
  • 看起来你必须在那里使用 2 个步骤。 1)创建一个有交集的列表。 2)检查两个列表中是否存在该数字,如果是,则将其附加到具有交叉点的列表中
  • @OneCricketeer (该评论很旧,但是)您可以看到这两个问题是不同的。这个问题是“正确的”多集交集,而另一个只是“list2 中的元素列表”。我不知道是否有很好的方法来解释它,但如果你知道,你可以编辑以澄清另一个问题。

标签: python python-2.7


【解决方案1】:

您可以为此使用collections.Counter,这将在您通过交叉路口时为每个元素提供在任一列表中找到的最低计数。

from collections import Counter

c = list((Counter(a) & Counter(b)).elements())

输出

[1, 1, 2, 3, 4]

【讨论】:

【解决方案2】:

简单,无需额外导入且易于调试 :)

缺点:列表b的值被改变了。如果您不想更改 b,请处理 b 的副本。

c = list()
for x in a:
    if x in b:
        b.remove(x)
        c.append(x)

【讨论】:

    【解决方案3】:

    使用 Counter 发布的公认解决方案很简单,但我认为这种使用字典的方法也可以工作并且可以更快 - 即使在未排序的列表上也是如此(没有真正提到该要求,但至少有一个其他解决方案的假设是这种情况)。

    a = [1, 1, 1, 2, 3, 4, 4]
    b = [1, 1, 2, 3, 3, 3, 4]
        
    def intersect(nums1, nums2):
        match = {}
        for x in a:
            if x in match:
                match[x] += 1
            else:
                match[x] = 1
                
        i = []
        for x in b:
            if x in match:
                i.append(x)
                match[x] -= 1
                if match[x] == 0:
                    del match[x]
    
        return i
    
    def intersect2(nums1, nums2):
        return list((Counter(nums1) & Counter(nums2)).elements())
    
    timeit intersect(a,b)
    100000 loops, best of 3: 3.8 µs per loop
    
    timeit intersect2(a,b)
    The slowest run took 4.90 times longer than the fastest. This could mean 
    that an intermediate result is being cached.
    10000 loops, best of 3: 20.4 µs per loop
    

    我用大小为 1000 和 10000 的随机整数列表进行了测试,它也更快。

    a = [random.randint(0,100) for r in xrange(10000)]
    b = [random.randint(0,100) for r in xrange(1000)]
    
    timeit intersect(a,b)
    100 loops, best of 3: 2.35 ms per loop
    
    timeit intersect2(a,b)
    100 loops, best of 3: 4.2 ms per loop
    

    更大的列表会有更多的共同元素

    a = [random.randint(0,10) for r in xrange(10000)]
    b = [random.randint(0,10) for r in xrange(1000)]
    
    timeit intersect(a,b)
    100 loops, best of 3: 2.07 ms per loop
    
    timeit intersect2(a,b)
    100 loops, best of 3: 3.41 ms per loop
    

    【讨论】:

    • ic 应该是同一个东西,也许吧? i 初始化后没有变化,然后返回一个空列表。
    • 错误.. 是的。已修复,谢谢。
    【解决方案4】:

    这也应该有效。

    a = [1, 1, 1, 2, 3, 4, 4]
    b = [1, 1, 2, 3, 3, 3, 4]
    c = []
    i, j = 0, 0
    while i < len(a) and j < len(b):
        if a[i] == b[j]:
            c.append(a[i])
            i += 1
            j += 1
        elif a[i] > b[j]:
            j += 1
        else:
            i += 1
    
    print(c) # [1, 1, 2, 3, 4]
    

    【讨论】:

      【解决方案5】:

      这也应该有效:

      def list_intersect(lisA, lisB):
          """ Finds the intersection of 2 lists including common duplicates"""
      
          Iset = set(lisA).intersection(set(lisB))
          Ilis = []
          for i in Iset:
              num = min(lisA.count(i), lisB.count(i))
              for j in range(num):
                  Ilis.append(i)
          return Ilis
      

      【讨论】:

        【解决方案6】:

        这样就可以了:

        from itertools import chain
        list(chain.from_iterable([(val,)*min(a.count(val), b.count(val)) for val in (set(a) & set(b))]))
        

        给予:

        [1, 1, 2, 3, 4]
        

        【讨论】:

          猜你喜欢
          • 2020-02-01
          • 2012-04-27
          • 1970-01-01
          • 1970-01-01
          • 2020-05-31
          • 1970-01-01
          • 2014-12-27
          • 2018-12-13
          相关资源
          最近更新 更多