如何构建一个生成器函数来完成跳过重复项

时间:2018-07-16 00:16:12

标签: python python-3.x unique

我想生成一个生成器函数,该函数遍历输入可迭代序列,一次生成一个元素,但跳过重复项。下面是一个示例代码:

numbers = [4, 5, 2, 6, 2, 3, 5, 8]
nums = unique(numbers)
    next(nums)
4
    next(nums)
5
    next(nums)
2
    next(nums)
6
    next(nums)
3
    next(nums)
8

有人知道为什么不打印此代码吗?

def unique(iterable):
    seen = set()
    for n in iterable:
        if n not in seen:
            seen.add(n)
            yield n

numbers = [4, 5, 2, 6, 2, 3, 5, 8]
nums = unique(numbers)
print(next(nums))

3 个答案:

答案 0 :(得分:4)

一个简单的唯一生成器将只保留set个已经看到的项目,例如:

def unique(nums):
    seen = set()
    for n in nums:
        if n not in seen:
            seen.add(n)
            yield n

In []:
numbers = [4, 5, 2, 6, 2, 3, 5, 8]
list(unique(numbers))

Out[]:
[4, 5, 2, 6, 3, 8]

答案 1 :(得分:3)

最简单的方法是use OrderedDict,这是一种在保留订单的同时进行重复数据删除的简单方法:

from collections import OrderedDict

def unique(nums):
    yield from OrderedDict.fromkeys(nums)

从技术上讲,它急切地运行(所有重复数据删除都在前面完成,然后迭代完全重复数据删除的OrderedDict),但是所有其他解决方案最终都需要构建等效的set,因此这会延迟第一个值的产生,但总体上却要完成相同的工作量(并且在使用C实现的OrderedDict的Python版本上,运行速度比使用set作为“可见”的生成器的手动滚动更快。商店)。它不适合的情况是无限输入可迭代项和有限但较大的可迭代项,在这些情况下,您很可能在完成之前会停止处理它们(在这种情况下,基于{{1}的惰性unique_everseen解决方案})。

在Python 3.6及更高版本上,plain dict preserves order(尽管it's not an official guarantee until 3.7),因此您甚至不需要导入:

set

答案 2 :(得分:0)

您是否需要发电机?为什么不只使用set

numbers = [4, 5, 2, 6, 2, 3, 5, 8]
for i in set(numbers):
    print(i)

如果您确实需要发电机:

def skipper(l):
    for i in set(l):
        yield i

for i in skipper(numbers):
    print(i)