列表交集算法实现仅使用python列表(不是集合)

时间:2013-02-13 01:18:23

标签: python

我一直在尝试在python中写下一个列表交集算法来处理重复。我是python和编程的新手,所以请原谅我,如果这听起来效率低下,但我无法想出其他任何东西。这里,L1和L2是有问题的两个列表,L是交集。

  1. 通过L1迭代
  2. 迭代L2
  3. 如果元素在L1和L2
  4. 将其添加到L
  5. 将其从L1和L2中删除
  6. 迭代L
  7. 将元素添加回L1和L2
  8. 我100%确定这不是Mathematica中用于评估列表交集的算法,但我无法真正提出任何更有效的方法。我不想在这个过程中修改L1和L2,因此我将两个列表添加回交集。有任何想法吗?我不想使用除列表之外的任何内置函数/数据类型,因此没有导入集或类似的东西。就我而言,这是一个算法和实现练习,而不是编程练习。

6 个答案:

答案 0 :(得分:1)

怎么样:

  1. 迭代L1
  2. 迭代L2
  3. 如果(在L1和L2中)而不在L - >中;添加到L
  4. 效率不是很高,但在代码中它看起来像这样(重复说明一点):

    >>> L1 = [1,2,3,3,4]
    >>> L2 = [2,3,4,4,5]
    >>> L = list()
    >>> for v1 in L1:
            for v2 in L2:
                if v1 == v2 and v1 not in L:
                    L.append(v1)
    >>> L
    [2,3,4]
    

    您可以通过检查元素是否已经在L中来避免从L1和L2中删除,如果不是则添加到L。那么L1和L2中是否有重复并不重要。

答案 1 :(得分:1)

编辑:我读错了标题,并浏览了内置部分。无论如何我会留在这里,可能会帮助别人。

您可以使用set类型实现此目的。

>>> a = [1,2,3,4]
>>> b = [3,4,5,6]
>>> c = list(set(a) & set(b))
>>> c
[3, 4]

答案 2 :(得分:1)

任何遍历L1的内容,每次迭代所有L2,都会花费二次时间。改进它的唯一方法是避免遍历所有L2。 (最后从L删除重复项也存在类似的问题。)

如果您使用set L2(和L),当然每个in L2步都是固定时间,因此整体算法是线性的。而且您始终可以构建自己的哈希表实现,而不是使用set。但这是很多工作。

使用二叉搜索树,甚至只是排序列表和binary_find函数,您可以在O(N log N)中执行此操作。并且binary_find更容易自己写。所以:

S2 = sorted(L2)
L = [element for element in L1 if binary_find(element, S2)]
S = remove_adjacent(sorted(L))

或者,更简单地说,排序L1,然后你不需要remove_adjacent

S1, S2 = sorted(L1), sorted(L2)
L = []
for element in S1:
    if binary_find(element, S2) and (not L or L[-1] != element):
        L.append(element)

无论哪种方式,这都是O(N log N),其中N是较长列表的长度。相比之下,原始是O(N ^ 2),其他答案是O(N ^ 3)。当然它有点复杂,但它仍然很容易理解。

你需要编写binary_find(如果适用,remove_adjacent),因为我假设你不想使用stdlib中的东西,如果你甚至不想使用额外的内置。但那真的很容易。例如:

def binary_find(element, seq):
    low, high = 0, len(seq), 
    while low != high:
        mid = (low + high) // 2
        if seq[mid] == element:
            return True
        elif seq[mid] < element:
            low = mid+1
        else:
            high = mid
    return False

def remove_adjacent(seq):
    ret = []
    last = object()
    for element in seq:
        if element != last:
            ret.append(element)
        last = element
    return ret

如果您甚至不想使用sortedlist.sort,也可以轻松编写自己的排序。

答案 3 :(得分:1)

这是一个更快的解决方案:

def intersect_sorted(a1, a2):
  """Yields the intersection of sorted lists a1 and a2, without deduplication.

  Execution time is O(min(lo + hi, lo * log(hi))), where lo == min(len(a1),
  len(a2)) and hi == max(len(a1), len(a2)). It can be faster depending on
  the data.
  """
  import bisect, math
  s1, s2 = len(a1), len(a2)
  i1 = i2 = 0
  if s1 and s1 + s2 > min(s1, s2) * math.log(max(s1, s2)) * 1.4426950408889634:
    bi = bisect.bisect_left
    while i1 < s1 and i2 < s2:
      v1, v2 = a1[i1], a2[i2]
      if v1 == v2:
        yield v1
        i1 += 1
        i2 += 1
      elif v1 < v2:
        i1 = bi(a1, v2, i1)
      else:
        i2 = bi(a2, v1, i2)
  else:  # The linear solution is faster.
    while i1 < s1 and i2 < s2:
      v1, v2 = a1[i1], a2[i2]
      if v1 == v2:
        yield v1
        i1 += 1
        i2 += 1
      elif v1 < v2:
        i1 += 1
      else:
        i2 += 1

它在O(min(n + m, n * log(m)))时间运行,其中n是长度的最小值,m是最大值。它同时迭代两个列表,尽可能跳过尽可能多的元素。

此处提供分析:http://ptspts.blogspot.ch/2015/11/how-to-compute-intersection-of-two.html

答案 4 :(得分:0)

  1. 制作临时名单。
  2. 遍历两个列表中的一个。哪个不重要。
  3. 对于每个元素,检查该元素是否存在于另一个列表(if element in list2)中,并且还不在您的临时列表中(语法相同)
  4. 如果两个条件均为真,请将其附加到临时列表中。

  5. 我觉得发布解决方案很糟糕,但它比我的文字更可读:

    def intersection(l1, l2):
        temp = []
    
        for item in l1:
            if item in l2 and item not in temp:
                temp.append(item)
    
        return temp
    

答案 5 :(得分:0)

计算保留订单和消除重复项的两个列表的交集的pythonic且有效的方法如下:

L1 = [1,2,3,3,4,4,4,5,6]
L2 = [2,4,6]
aux = set()
L = [x for x in L1 if x in L2 and not (x in aux or aux.add(x)) ]

解决方案使用set&#34; aux&#34;存储已添加到结果列表中的元素。

请注意,您不需要&#34;导入&#34;集,因为它们是Python中的本机数据类型。但是,如果您坚持不使用集合,则可以选择使用列表的效率较低的版本:

L1 = [1,2,3,3,4,4,4,5,6]
L2 = [2,4,6]
aux = []
L = [x for x in L1 if x in L2 and not (x in aux or aux.append(x)) ]