通常,你可以使用多种方法对一个或多个列表进行去重,无论是否按顺序。
以下是一种不保持顺序的去重两个列表的方法:
>>> A=[1,3,5,'a','c',7]
>>> B=[1,2,3,'c','b','a',6]
>>> set(A+B)
set(['a', 1, 'c', 3, 5, 6, 7, 2, 'b'])
这里有一种方法可以保持顺序:
>>> seen=set()
>>> [e for e in A+B if e not in seen and (seen.add(e) or True)]
[1, 3, 5, 'a', 'c', 7, 2, 'b', 6]
问题在于,为了使用这些方法,所有元素都必须是可哈希的:
>>> set([np.array(range(10)), 22])
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unhashable type: 'numpy.ndarray'
解决这个问题的一种方法是使用每个元素的repr:
>>> set([repr(e) for e in [np.array(range(10)), 22]])
set(['22', 'array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])'])
或者使用
frozenset:
>>> set(frozenset(e) for e in [np.array(range(10)), np.array(range(2))])
set([frozenset([0, 1]), frozenset([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])])
在您的情况下,frozenset方法不适用于列表的列表:
>>> set(frozenset(e) for e in [[np.array(range(10)), np.array(range(2))],[np.array(range(5))
]])
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 1, in <genexpr>
TypeError: unhashable type: 'numpy.ndarray'
所以您需要使用扁平化的列表。
如果子列表的repr是其唯一性的明确证明,您可以这样做:
from collections import OrderedDict
import numpy as np
A = [['foo', 123], ['bar', np.array(range(10))], ['baz', 345]]
B = [['foo', 123], ['bar', np.array(range(10))], ['meow', 456]]
seen=OrderedDict((repr(e),0) for e in B)
newA=[]
for e in A+B:
key=repr(e)
if key in seen:
if seen[key]==0:
newA.append(e)
seen[key]=1
else:
seen[key]=1
newA.append(e)
print newA
由于repr
函数返回一个字符串,可以被eval
函数用于重新创建列表,这是相当明确的测试,但我不能完全确定。它取决于列表中有什么。
例如,lambda的repr无法重新创建lambda:
>>> repr(lambda x:x)
'<function <lambda> at 0x10710ec08>'
但是,'<function <lambda> at 0x10710ec08>'
的字符串值仍然是明确唯一的,因为 0x10710ec08
部分是 lambda 在内存中的地址(在 cPython 中是这样的)。
您还可以像我上面提到的那样--使用 frozenset 中的扁平列表作为已看到或未看到内容的签名:
def flatten(LoL):
for el in LoL:
if isinstance(el, collections.Iterable) and not isinstance(el, basestring):
for sub in flatten(el):
yield sub
else:
yield el
newA=[]
seen=set()
for e in A+B:
fset=frozenset(flatten(e))
if fset not in seen:
newA.append(e)
seen.add(fset)
print newA
所以如果你有奇怪的对象既不可哈希又不唯一的
repr
字符串对象在A和B中,那么你就没办法了。根据你的示例,其中一种方法应该有效。
np.array
实例是否完全可比较? - salezicanp.arange(10) == np.arange(10)
,这会导致一个布尔数组而不是单个值(这是非常明确的设计)。通常你会使用集合来解决这个问题,但是numpy数组不可哈希。因此,最简单的方法是将数组转换为不可变元组,并将每个子列表转换为元组或集合。然后你就可以进行“常规”的集合交集操作了。 - Joe Kington