查找列表中不常见的元素

Posted

技术标签:

【中文标题】查找列表中不常见的元素【英文标题】:Find non-common elements in lists 【发布时间】:2012-07-06 02:16:18 【问题描述】:

我正在尝试编写一段可以自动分解表达式的代码。例如, 如果我有两个列表 [1,2,3,4] 和 [2,3,5],代码应该能够找到两个列表 [2,3] 中的共同元素,并将其余部分组合起来元素一起在一个新列表中,即 [1,4,5]。

来自这个帖子:How to find list intersection? 我看到共同的元素可以通过

找到
set([1,2,3,4]&set([2,3,5]). 

有没有一种简单的方法可以从每个列表中检索非常见元素,在我的示例中是 [1,4] 和 [5]?

我可以继续做一个 for 循环:

lists = [[1,2,3,4],[2,3,5]]
conCommon = []
common = [2,3]
for elem in lists:
    for elem in eachList:
    if elem not in common:
        nonCommon += elem

但这似乎是多余且低效的。 Python 是否提供任何方便的函数来做到这一点?提前致谢!!

【问题讨论】:

您想要获得单独的列表,例如 [1,4] 和 [5],还是单个列表 [1,4,5]? 【参考方案1】:

所有好的解决方案,从基本的 DSA 风格到使用内置函数:

# Time: O(2n)
def solution1(arr1, arr2):
  map = 
  maxLength = max(len(arr1), len(arr2))
  for i in range(maxLength):
    if(arr1[i]):
      if(not map.get(arr1[i])):
        map[arr1[i]] = [True, False]
      else:
        map[arr1[i]][0] = True
    if(arr2[i]):
      if(not map.get(arr2[i])):
        map[arr2[i]] = [False, True]
      else:
        map[arr2[i]][1] = False

  res = [];
  for key, value in map.items():
    if(value[0] == False or value[1] == False):
      res.append(key)

  return res

def solution2(arr1, arr2):
  return set(arr1) ^ set(arr2)

def solution3(arr1, arr2):
  return (set(arr1).difference(arr2), set(arr2).difference(arr1))

def solution4(arr1, arr2):
  return set(arr1).__xor__(set(arr2))

print(solution1([1,2,3], [2,4,6]))
print(solution2([1,2,3], [2,4,6]))
print(solution3([1,2,3], [2,4,6]))
print(solution4([1,2,3], [2,4,6]))

【讨论】:

【参考方案2】:

您可以使用 symmetric_difference 命令

x = 1,2,3 y = 2,3,4

z = set.difference(x,y)

输出将是:z = 1,4

【讨论】:

【参考方案3】:

这应该得到共同的和剩余的元素

lis1=[1,2,3,4,5,6,2,3,1]
lis2=[4,5,8,7,10,6,9,8]

common = list(dict.fromkeys([l1 for l1 in lis1 if l1 in lis2]))
remaining = list(filter(lambda i: i not in common, lis1+lis2))

common = [4, 5, 6]

remaining = [1, 2, 3, 2, 3, 1, 8, 7, 10, 9, 8]

【讨论】:

【参考方案4】:

老问题,但看起来 python 有一个内置函数可以提供您正在寻找的内容:.difference()

示例

list_one = [1,2,3,4]
list_two = [2,3,5]

one_not_two = set(list_one).difference(list_two)
# set([1, 4])

two_not_one = set(list_two).difference(list_one)
# set([5])

这也可以写成:

one_not_two = set(list_one) - set(list_two)

时机

我对两者都进行了一些计时测试,似乎.difference() 有轻微的优势,大约为 10 - 15%,但每种方法需要大约八分之一秒来过滤 1M 项(500 到 500 之间的随机整数) 100,000),所以除非您非常对时间敏感,否则它可能无关紧要。

其他说明

看来 OP 正在寻找提供两个单独列表(或集合)的解决方案 - 第一个列表包含第二个不包含的项目,反之亦然。以前的大多数答案都返回一个包含所有项目的列表或集合。

还有一个问题是,第一个列表中可能重复的项目是否应该计算多次,还是只计算一次。

如果 OP 想要维护重复项,可以使用列表推导,例如:

one_not_two = [ x for x in list_one if x not in list_two ]
two_not_one = [ x for x in list_two if x not in list_one ]

...这与原始问题中提出的解决方案大致相同,只是更简洁一些。此方法将保留原始列表中的重复项,但对于较大的数据集相当(如多个数量级)慢。

【讨论】:

【参考方案5】:

您可以使用.__xor__ 属性方法。

set([1,2,3,4]).__xor__(set([2,3,5]))

a = set([1,2,3,4])
b = set([2,3,5])
a.__xor__(b)

【讨论】:

【参考方案6】:

你可以使用Intersection的概念来处理这类问题。

b1 = [1,2,3,4,5,9,11,15]
b2 = [4,5,6,7,8]
set(b1).intersection(b2)
Out[22]: 4, 5

使用此代码的最大好处是它对于大数据也非常有效。当我使用这个逻辑时,我有 607139 的 b1 和 296029 的 b2 元素,我在 2.9 秒内得到了结果。

【讨论】:

这没有回答原始问题。问是相反的。【参考方案7】:

sets 使用对称差分运算符(又名 XOR 运算符):

>>> set([1,2,3]) ^ set([3,4,5])
set([1, 2, 4, 5])

【讨论】:

哦哇谢谢!!上面的代码是否需要与 set([1,2,3])&set([3,4,5]) 相同的计算时间和内存空间?还是对代码性能没有显着影响? 这是实现目标的最有效方式。它的复杂性与& 的数量级相同(即与集合中的元素数量成线性关系)。

以上是关于查找列表中不常见的元素的主要内容,如果未能解决你的问题,请参考以下文章

使用列表推导查找列表中的元素,其中列表中的所有元素都是因子

20172308 《程序设计与数据结构》第五周学习总结

找出另一个数组列表中不存在的数组列表的元素

如何在自定义链表实现中找到最常见的元素?

初学python之以时间复杂度去理解列表常见使用方法

向下滚动以查找文本在 android 模拟器中不起作用的元素