如何从列表中删除重复项,同时保持顺序?使用集合删除重复项会破坏原始顺序。 是否有内置的或python的习语?
当前回答
sequence = ['1', '2', '3', '3', '6', '4', '5', '6']
unique = []
[unique.append(item) for item in sequence if item not in unique]
unique→[1、(2)、(3)、(6)、(4)、(5)]
其他回答
在CPython 3.6+(以及从Python 3.7+开始的所有其他Python实现)中,字典是有序的,因此从可迭代对象中删除重复项同时保持其原始顺序的方法是:
>>> list(dict.fromkeys('abracadabra'))
['a', 'b', 'r', 'c', 'd']
在Python 3.5及以下版本(包括Python 2.7)中,使用OrderedDict。我的计时表明,这是Python 3.5的各种方法中最快和最短的(当它获得C实现时;在3.5之前,它仍然是最清晰的解决方案,尽管不是最快的)。
>>> from collections import OrderedDict
>>> list(OrderedDict.fromkeys('abracadabra'))
['a', 'b', 'r', 'c', 'd']
如果你需要一个班轮,那么这可能会有帮助:
reduce(lambda x, y: x + y if y[0] not in x else x, map(lambda x: [x],lst))
... 应该工作,但纠正我,如果我错了
借用Haskell为列表定义nub函数时使用的递归思想,这将是一种递归方法:
def unique(lst):
return [] if lst==[] else [lst[0]] + unique(filter(lambda x: x!= lst[0], lst[1:]))
例如:
In [118]: unique([1,5,1,1,4,3,4])
Out[118]: [1, 5, 4, 3]
我对不断增长的数据大小进行了尝试,看到了次线性的时间复杂度(不是确定的,但建议这对于普通数据应该没问题)。
In [122]: %timeit unique(np.random.randint(5, size=(1)))
10000 loops, best of 3: 25.3 us per loop
In [123]: %timeit unique(np.random.randint(5, size=(10)))
10000 loops, best of 3: 42.9 us per loop
In [124]: %timeit unique(np.random.randint(5, size=(100)))
10000 loops, best of 3: 132 us per loop
In [125]: %timeit unique(np.random.randint(5, size=(1000)))
1000 loops, best of 3: 1.05 ms per loop
In [126]: %timeit unique(np.random.randint(5, size=(10000)))
100 loops, best of 3: 11 ms per loop
我还认为有趣的是,这可以很容易地通过其他运算推广到唯一性。是这样的:
import operator
def unique(lst, cmp_op=operator.ne):
return [] if lst==[] else [lst[0]] + unique(filter(lambda x: cmp_op(x, lst[0]), lst[1:]), cmp_op)
例如,你可以传入一个函数,它使用舍入到同一个整数的概念,就像它是“相等”的唯一性目的,像这样:
def test_round(x,y):
return round(x) != round(y)
那么unique(some_list, test_round)将提供列表中唯一的元素,其中唯一性不再意味着传统的相等性(这是通过使用任何类型的基于集或基于字典键的方法来解决这个问题),而是意味着对于每个元素可能舍入的整数K,只取第一个舍入到K的元素,例如:
In [6]: unique([1.2, 5, 1.9, 1.1, 4.2, 3, 4.8], test_round)
Out[6]: [1.2, 5, 1.9, 4.2, 3]
1. 这些解决方案很好…… 为了在保留秩序的同时删除重复项,本页其他地方提出了优秀的解决方案:
seen = set()
[x for x in seq if not (x in seen or seen.add(x))]
以及变化,例如:
seen = set()
[x for x in seq if x not in seen and not seen.add(x)]
确实很受欢迎,因为它们简单、极简,并部署了正确的哈希以获得最佳效率。关于这些方法的主要抱怨似乎是,将方法see .add(x)“返回”的不变量None用作逻辑表达式中的常量(因此是多余的/不必要的)值(只是为了它的副作用)是笨拙和/或令人困惑的。
2. …but they waste one hash lookup per iteration. Surprisingly, given the amount of discussion and debate on this topic, there is actually a significant improvement to the code that seems to have been overlooked. As shown, each "test-and-set" iteration requires two hash lookups: the first to test membership x not in seen and then again to actually add the value seen.add(x). Since the first operation guarantees that the second will always be successful, there is a wasteful duplication of effort here. And because the overall technique here is so efficient, the excess hash lookups will likely end up being the most expensive proportion of what little work remains.
3.相反,让布景完成它的工作吧! 注意,上面的例子只调用set。加上预见,这样做总是会导致集合成员的增加。集合本身永远没有机会拒绝副本;我们的代码片段实际上已经篡夺了这个角色。使用显式的两步测试和设置代码剥夺了set自身排除这些重复的核心能力。
4. 单哈希查找代码: 下面的版本将每次迭代的哈希查找次数减少了一半,从两次减少到只有一次。
seen = set()
[x for x in seq if len(seen) < len(seen.add(x) or seen)]
对于另一个非常古老的问题的一个非常晚的回答:
itertools食谱有一个函数可以做到这一点,使用了见集技术,但是:
处理标准键函数。 不使用不体面的黑客。 通过预绑定优化循环。加,而不是查N次。(f7也这样做,但有些版本没有。) 通过使用ifilterfalse优化循环,因此只需遍历Python中唯一的元素,而不是所有元素。(当然,您仍然在ifilterfalse中遍历所有它们,但这是在C中,而且要快得多。)
Is it actually faster than f7? It depends on your data, so you'll have to test it and see. If you want a list in the end, f7 uses a listcomp, and there's no way to do that here. (You can directly append instead of yielding, or you can feed the generator into the list function, but neither one can be as fast as the LIST_APPEND inside a listcomp.) At any rate, usually, squeezing out a few microseconds is not going to be as important as having an easily-understandable, reusable, already-written function that doesn't require DSU when you want to decorate.
和所有的食谱一样,它也有更多的版本。
如果你只想要无键的情况,你可以简化为:
def unique(iterable):
seen = set()
seen_add = seen.add
for element in itertools.ifilterfalse(seen.__contains__, iterable):
seen_add(element)
yield element
推荐文章
- 证书验证失败:无法获得本地颁发者证书
- 当使用pip3安装包时,“Python中的ssl模块不可用”
- 无法切换Python与pyenv
- Python if not == vs if !=
- 如何从scikit-learn决策树中提取决策规则?
- 为什么在Mac OS X v10.9 (Mavericks)的终端中apt-get功能不起作用?
- 将旋转的xtick标签与各自的xtick对齐
- 为什么元组可以包含可变项?
- 如何合并字典的字典?
- 如何创建类属性?
- 不区分大小写的“in”
- 在Python中获取迭代器中的元素个数
- 解析日期字符串并更改格式
- 使用try和。Python中的if
- 如何在Python中获得所有直接子目录