我有n个数字列表。我想确保每个列表都包含特定于该列表的唯一元素。也就是说,没有任何“共享”的重复项跨越任何其他列表。
对于两个列表来说,这很容易做到,但对于n个列表来说则有点棘手。
e.g.
mylist = [
[1, 2, 3, 4],
[2, 5, 6, 7],
[4, 2, 8, 9]
]
成为:
mylist = [
[1, 3],
[5, 6, 7],
[8, 9]
]
from collections import Counter
from itertools import chain
mylist = [
[1,2,3,4],
[2,5,6,7,7],
[4,2,8,9]
]
counts = Counter(chain(*map(set,mylist)))
[[i for i in sublist if counts[i]==1] for sublist in mylist]
#[[1, 3], [5, 6, 7, 7], [8, 9]]
chain(*mylist)
гҖӮйқһеёёеҘҪгҖӮе“Һе‘ҖпјҢжҲ‘з”ҡиҮідёҚйңҖиҰҒеғҸжҲ‘зҡ„зӯ”жЎҲдёӯйӮЈж ·дҪҝз”Ё.get()
пјҢеӣ дёәеҪ“然е®ғжҖ»жҳҜиў«е®ҡд№үзҡ„гҖӮжҲ‘еҲ йҷӨдәҶжҲ‘зҡ„зӯ”жЎҲпјҢеӣ дёәдҪ зҡ„зӯ”жЎҲеҮ д№Һе®Ңе…ЁзӣёеҗҢпјҢдҪҶжӣҙеҠ дёҘи°ЁгҖӮ - ninjageckochain
和Counter
构造函数都不是O(N)
的任何理由。 - ninjageckomap(set,mylist)
而不是mylist
)。 - ninjagecko这个方法可以在线性时间内完成,需要进行两次遍历。我假设您希望在列表中保留重复项;如果不需要,这个方法可以简化一些:
>>> import collections, itertools
>>> counts = collections.defaultdict(int)
>>> for i in itertools.chain.from_iterable(set(l) for l in mylist):
... counts[i] += 1
...
>>> for l in mylist:
... l[:] = (i for i in l if counts[i] == 1)
...
>>> mylist
[[1, 3], [5, 6, 7], [8, 9]]
由于您不关心顺序,因此可以使用集合减法轻松删除重复项,并将其转换回列表。以下是一个巨大的一行代码:
>>> mylist = [
... [1, 2, 3, 4],
... [2, 5, 6, 7],
... [4, 2, 8, 9]
... ]
>>> mynewlist = [list(set(thislist) - set(element for sublist in mylist for element in sublist if sublist is not thislist)) for thislist in mylist]
>>> mynewlist
[[1, 3], [5, 6, 7], [8, 9]]
注意:这种方法并不是很高效,因为对于每一行都要重新计算重复项。是否存在问题取决于您的数据大小。
O(N)
解决方案,而非O(N^2)
的解决方案,3)我看到了一个多余的enumerate
,显得粗心。我仍然认为#2理由足以导致投票否决,但现在我发现“is not”部分是有用的,enumerate
已被移除,你还考虑了性能问题,所以我撤销了我的投票否决。 - ninjageckol=[list(set(t) - set(x for s in m for x in s if s is not t)) for t in m]
,但它可能不太容易自我说明如何使用列表推导式。:)不确定您所说的缩进单行代码是什么意思。 - wim使用set()是正确的方法,虽然你不一定要使用列表推导。
无需额外导入:
mylist = [
[1, 2, 3, 4],
[2, 5, 6, 7],
[4, 2, 8, 9]
]
>>> result_list = []
>>> for test_list in mylist:
... result_set = set(test_list)
... for compare_list in mylist:
... if test_list != compare_list:
... result_set = result_set - set(compare_list)
... result_list.append(result_set)
...
>>> result_list
[set([1, 3]), set([5, 6, 7]), set([8, 9])]
Counter
构建所有共同数字的集合,然后执行一个集合差异操作:from collections import Counter
def disjoin(lsts):
c = Counter(num for lst in lsts for num in lst)
common = set(x for x,v in c.items() if v > 1)
result = []
for lst in lsts:
result.append(set(lst) - common)
return result
例子:
>>> remove_common(mylist)
[set([1, 3]), set([5, 6, 7]), set([8, 9])]
default_dict
)来构建一个“已看到”的列表。用查找匹配的“已看到”生成器替换每个mylist
列表(我将其称为sublist
),如果找到,则不在最终的sublist
中包含它。如果没有找到,则将其添加到包中。 - yurisichmylist = [[1, 2, 2], [3]]
的预期输出是什么? - wim