从列表中删除重复的子列表
Remove duplicate sublists from a list
如果我有这样一个列表:
mylist = [[1,2,3], ['a', 'c'], [3,4,5],[1,2], [3,4,5], ['a', 'c'], [3,4,5], [1,2]]
删除重复子列表的最佳方法是什么?
现在我用this:
y, s = [ ], set( )
for t in mylist:
w = tuple( sorted( t ) )
if not w in s:
y.append( t )
s.add( w )
可以,但是不知道有没有更好的办法?更多 python 之类的东西?
将元素转换为元组*,然后将其整体转换为集合,然后将所有内容转换回列表:
m = [[1,2,3], ['a', 'c'], [3,4,5],[1,2], [3,4,5], ['a', 'c'], [3,4,5], [1,2]]
print [list(i) for i in set(map(tuple, m))]
*我们正在转换为元组,因为列表是不可散列的(因此我们不能对它们使用 set
好吧,由于 set
本质上是重复数据删除,您的第一直觉可能是 set(mylist)
。然而,这并不完全有效:
In [1]: mylist = [[1,2,3], ['a', 'c'], [3,4,5],[1,2], [3,4,5], ['a', 'c'], [3,4,5], [1,2]]
In [2]: set(mylist)
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-2-b352bcae5975> in <module>()
----> 1 set(mylist)
TypeError: unhashable type: 'list'
这是因为 set
s 仅适用于 iterable
s 的可散列元素(并且由于 list
s 是可变的,因此它们不可散列)。
相反,您只需支付将子列表转换为子元组的费用就可以做到这一点:
In [3]: set([tuple(x) for x in mylist])
Out[3]: {(1, 2), (1, 2, 3), (3, 4, 5), ('a', 'c')}
或者,如果您真的需要再次列出列表:
In [4]: [list(x) for x in set([tuple(x) for x in mylist])]
Out[4]: [[1, 2], [3, 4, 5], ['a', 'c'], [1, 2, 3]]
嗯,这对你的情况有用:
mylist2 = set(map(tuple, mylist))
print(mylist2) # ('a', 'c'), (3, 4, 5), (1, 2), (1, 2, 3)}
这行得通,因为它将您的子列表更改为元组,在您的情况下是可散列的。所以 set 可以把它们做成一个独特的。
如果你真的希望输出是列表的列表,你可以这样做:
print(list(map(list,mylist2))) # [['a', 'c'], [3, 4, 5], [1, 2], [1, 2, 3]]
您可以使用 OrderedDict.fromkeys
从列表中过滤出重复项,同时仍保留顺序:
>>> from collections import OrderedDict
>>> mylist = [[1,2,3], ['a', 'c'], [3,4,5],[1,2], [3,4,5], ['a', 'c'], [3,4,5], [1,2]]
>>> map(list, OrderedDict.fromkeys(map(tuple, mylist)))
[[1, 2, 3], ['a', 'c'], [3, 4, 5], [1, 2]]
>>>
map(tuple, mylist)
是必需的,因为字典键必须是可散列的(列表不是,因为您可以从中 add/remove 项目)。
您不需要排序,您复制的代码中的排序是出于不同原因排序:
seen,out = set(), []
for ele in mylist:
tp = tuple(ele)
if tp not in seen:
out.append(ele)
seen.add(tp)
因为你的问题中有 sorted(t)
,我假设你认为 [1,2]
是 [2,1]
的副本
如果这是真的,我会对内部列表(可散列的)使用 frozenset,并且不会关心子列表的顺序。
所以像这样:
set(frozenset(sublist) for sublist in mylist)
如果顺序和结构(列表列表)不重要,您可以使用
set(map(tuple, my_list))
如果它们确实重要,您可以使用列表理解
[e for i,e in enumerate(my_list) if e not in my_list[:i]]
只保留每个元素的第一个副本,因此每个元素只保留一个。它稍微慢一点
In [16]: timeit.timeit('[e for i,e in enumerate(my_list) if e not in my_list[:i]]', setup="my_list = [[1,2,3], ['a', 'c'], [3,4,5],[1,2], [3,4,5], ['a', 'c'], [3,4,5], [1,2]]")
Out[16]: 1.9146944019994407
In [17]: timeit.timeit('set(map(tuple, my_list))', setup="my_list = [[1,2,3], ['a', 'c'], [3,4,5],[1,2], [3,4,5], ['a', 'c'], [3,4,5], [1,2]]")
Out[17]: 1.3857673469974543
但如果您关心速度,您可能应该尝试一种循环的方法。
如果我有这样一个列表:
mylist = [[1,2,3], ['a', 'c'], [3,4,5],[1,2], [3,4,5], ['a', 'c'], [3,4,5], [1,2]]
删除重复子列表的最佳方法是什么?
现在我用this:
y, s = [ ], set( )
for t in mylist:
w = tuple( sorted( t ) )
if not w in s:
y.append( t )
s.add( w )
可以,但是不知道有没有更好的办法?更多 python 之类的东西?
将元素转换为元组*,然后将其整体转换为集合,然后将所有内容转换回列表:
m = [[1,2,3], ['a', 'c'], [3,4,5],[1,2], [3,4,5], ['a', 'c'], [3,4,5], [1,2]]
print [list(i) for i in set(map(tuple, m))]
*我们正在转换为元组,因为列表是不可散列的(因此我们不能对它们使用 set
好吧,由于 set
本质上是重复数据删除,您的第一直觉可能是 set(mylist)
。然而,这并不完全有效:
In [1]: mylist = [[1,2,3], ['a', 'c'], [3,4,5],[1,2], [3,4,5], ['a', 'c'], [3,4,5], [1,2]]
In [2]: set(mylist)
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-2-b352bcae5975> in <module>()
----> 1 set(mylist)
TypeError: unhashable type: 'list'
这是因为 set
s 仅适用于 iterable
s 的可散列元素(并且由于 list
s 是可变的,因此它们不可散列)。
相反,您只需支付将子列表转换为子元组的费用就可以做到这一点:
In [3]: set([tuple(x) for x in mylist])
Out[3]: {(1, 2), (1, 2, 3), (3, 4, 5), ('a', 'c')}
或者,如果您真的需要再次列出列表:
In [4]: [list(x) for x in set([tuple(x) for x in mylist])]
Out[4]: [[1, 2], [3, 4, 5], ['a', 'c'], [1, 2, 3]]
嗯,这对你的情况有用:
mylist2 = set(map(tuple, mylist))
print(mylist2) # ('a', 'c'), (3, 4, 5), (1, 2), (1, 2, 3)}
这行得通,因为它将您的子列表更改为元组,在您的情况下是可散列的。所以 set 可以把它们做成一个独特的。
如果你真的希望输出是列表的列表,你可以这样做:
print(list(map(list,mylist2))) # [['a', 'c'], [3, 4, 5], [1, 2], [1, 2, 3]]
您可以使用 OrderedDict.fromkeys
从列表中过滤出重复项,同时仍保留顺序:
>>> from collections import OrderedDict
>>> mylist = [[1,2,3], ['a', 'c'], [3,4,5],[1,2], [3,4,5], ['a', 'c'], [3,4,5], [1,2]]
>>> map(list, OrderedDict.fromkeys(map(tuple, mylist)))
[[1, 2, 3], ['a', 'c'], [3, 4, 5], [1, 2]]
>>>
map(tuple, mylist)
是必需的,因为字典键必须是可散列的(列表不是,因为您可以从中 add/remove 项目)。
您不需要排序,您复制的代码中的排序是出于不同原因排序:
seen,out = set(), []
for ele in mylist:
tp = tuple(ele)
if tp not in seen:
out.append(ele)
seen.add(tp)
因为你的问题中有 sorted(t)
,我假设你认为 [1,2]
是 [2,1]
如果这是真的,我会对内部列表(可散列的)使用 frozenset,并且不会关心子列表的顺序。
所以像这样:
set(frozenset(sublist) for sublist in mylist)
如果顺序和结构(列表列表)不重要,您可以使用
set(map(tuple, my_list))
如果它们确实重要,您可以使用列表理解
[e for i,e in enumerate(my_list) if e not in my_list[:i]]
只保留每个元素的第一个副本,因此每个元素只保留一个。它稍微慢一点
In [16]: timeit.timeit('[e for i,e in enumerate(my_list) if e not in my_list[:i]]', setup="my_list = [[1,2,3], ['a', 'c'], [3,4,5],[1,2], [3,4,5], ['a', 'c'], [3,4,5], [1,2]]")
Out[16]: 1.9146944019994407
In [17]: timeit.timeit('set(map(tuple, my_list))', setup="my_list = [[1,2,3], ['a', 'c'], [3,4,5],[1,2], [3,4,5], ['a', 'c'], [3,4,5], [1,2]]")
Out[17]: 1.3857673469974543
但如果您关心速度,您可能应该尝试一种循环的方法。