任务:
开发一个clean_list (list_to_clean)
函数,
它带有一个参数-任意长度的任何值(字符串,整数和浮点数)的列表,
并返回一个具有相同值但没有重复项的列表。这意味着,如果原始列表在多个实例中都存在一个值,则该值的第一个“实例”将保留在原位置,而第二个,第三个等等将被删除。
示例:
函数调用:clean_list ([32, 32.1, 32.0, -32, 32, '32'])
返回:[32, 32.1, 32.0, -32, '32']
我的代码:
def clean_list(list_to_clean):
no_dubl_lst = [value for _, value in set((type(x), x) for x in list_to_clean)]
return no_dubl_lst
print(clean_list([32, 32.1, 32.0, -32, 32, '32']))
结果:
[32.1, 32, -32, 32.0, '32']
但是我如何恢复原始订单?
答案 0 :(得分:4)
这里有两个问题,因此出于回答的目的,我将两者都列出。
Removing duplicates in lists建议将中间体set
构造为最快的方法。如果一个元素等于当前元素,则认为它存在于集合中。
在您的情况下,您不仅需要值,还需要类型相等。
那么,为什么不构造一组中间元组(value, type)
?
unique_list = [v for v,t in {(v,type(v)) for v in orig_list}]
使用Does Python have an ordered set?中的“有序集”容器。例如:
从3.7(和CPython 3.6,其中是实现细节)开始,常规dict
保留插入顺序:
unique_list = [v for v,t in dict.fromkeys((v,type(v)) for v in orig_list)]
对于所有版本(在3.6+中也存在,因为它还有其他方法),请使用collections.OrderedDict
:
import collections
unique_list = [v for v,t in collections.OrderedDict.fromkeys((v,type(v)) for v in orig_list)]
作为参考,与撰写本文时的其他答案相比,timeit
在我的计算机(3.7.4 win64)上得到的结果:
In [24]: l=[random.choice((int,float,lambda v:str(int(v))))(random.random()*1000) for _ in range(100000)]
In [26]: timeit dict_fromkeys(l) #mine
38.6 ms ± 179 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)
In [34]: timeit ordereddict_fromkeys(l) #mine with OrderedDict
53.3 ms ± 233 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)
In [25]: timeit build_with_filter(l) #Ch3steR's O(n)
48.7 ms ± 214 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)
In [28]: timeit dict_with_none(l) #Patrick Artner's
46.8 ms ± 377 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)
In [30]: timeit listcompr_side_effect(l) #CDJB's
55.5 ms ± 801 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)
答案 1 :(得分:3)
放置集,检查集方法很好。您也可以将任何dict()
用于python 3.7+(键保持输入顺序)或OrderedDict用于python 3.7以下版本:
def clean_list(list_to_clean):
ord_dic = dict
import sys
major,minor,_,_,_ = sys.version_info
if major < 3 or major == 3 and minor < 7:
# dict not yet input ordered
from collections import OrderedDict
no_dubl_lst = OrderedDict(((type(a),a),None) for a in list_to_clean)
else:
# dict is input ordered by default
no_dubl_lst = dict(((type(a),a),None) for a in list_to_clean)
return list(b for _,b in no_dubl_lst.keys()) # only produce the actual data
print(clean_list([32, 32.1, 32.0, -32, 32, '32']))
产生:
[32, 32.1, 32.0, -32, '32']
基本上,字典键的行为类似于一组键(仅会使用第一个,而后面的键会覆盖第一个的None
值)-但它们是有序的。
如果您使用的是3.7+简易版
def clean_list(list_to_clean):
# dict is input ordered by default
no_dubl_lst = dict(((type(a),a),None) for a in list_to_clean)
类似于ivan_pozdeev的答案-在我创建答案时,他删除/编辑/取消删除了具有更多内容的第一个答案。
您将获得我的自动版本检测功能,因此请不要将其删除。
答案 2 :(得分:2)
您尝试一下。
像您要求的那样第一个实例保留在原处,其余的都会被删除。
(请注意,这个是O(n^2)
)
_list=[32, 32.1, 32.0, -32, 32, '32']
_clist=[]
for i in _list:
if (i,type(i),) not in _clist:
_clist.append((i,type(i),))
cleaned_list=list(zip(*_clist))[0]
print(cleaned_list)
#(32, 32.1, 32.0, -32, '32')
一种O(n)
方法,具有额外的O(n)
空间。
_list=[32, 32.1, 32.0, -32, 32, '32']
unique=set()
cleaned=[]
for i in _list:
if (i,type(i),) not in unique:
unique.add((i,type(i),))
cleaned.append(i)
注意:
请检查timeit
的答案,以对发布的几个答案进行stock
分析。
答案 3 :(得分:0)
为此,我的版本是O(n)
编辑后的答案:现在,它比普通设置更尊重类型
def clean_list(list_to_cealn):
unique_items = set()
result = []
for x in list_to_cealn:
item = (type(x), x)
if item not in unique_items:
result.append(x)
unique_items.add(item)
return result
答案 4 :(得分:0)
适应方法here:
def clean_list(list_to_clean):
seen = set()
seen_add = seen.add
no_dubl_lst = [value for _, value in [(type(x), x) for x in list_to_clean if not ( (type(x), x) in seen or seen_add((type(x), x)))]]
return no_dubl_lst
print(clean_list([32, 32.1, 32.0, -32, 32, '32']))
输出:
[32, 32.1, 32.0, -32, '32']
答案 5 :(得分:0)
保留dict
而不是集合,以将(x, type(x))
映射到x
。
我们第一次看到x
类型为y
的情况,并不是(x,y)
是字典中的键。
但是,有一种实用的方法可以同时更新dict
和以获得所需的值:使用setdefault
方法。
在下面,我们首先创建元组(并使用:=
来记住它)并检查它是否在seen
中。这将不是我们第一次遇到特定类型的x
。由于t not in seen
是True
,因此我们将评估对setdefault
的调用。然后,该方法调用将返回x
的值,但也有副作用,请执行seen[t] = x
。现在,当我们发现重复项时,t not in seen
将返回False
,从而完全避免了seen.setdefault
的调用,从而跳过了x
的重复值。由于我们仅迭代原始输入,因此原始订单保留在输出中。
seen = {}
no_dubl_lst = [seen.setdefault(t, x)
for x in list_to_clean
if (t:=(x, type(x))) not in seen]