我有一个有序的待处理列表,包括一些重复项,我只想处理第一次出现。现在,我在Python v2.7中这样做:
seen = set()
for (value, fmt) in formats:
if fmt not in seen:
seen.add(fmt)
process(value, fmt)
是否有同时将新元素插入seen
并检测它是否已存在? (这样可以避免在fmt
中重复查找set
。)
seen = set()
for (value, fmt) in formats:
# myInsert() would return true if item was not already present.
if seen.myInsert(fmt):
process(value, fmt)
或者,或者,我可以以某种方式过滤我的formats
以在循环之前排除重复的条目吗?
unique_formats = removeDuplicates(formats, key=itemgetter(1))
for (value, fmt) in unique_formats:
process(value, fmt)
答案 0 :(得分:2)
您可以在add()
之前和之后获取集合的长度。如果它没有改变,格式已经在集合中。
seen = set()
for (value, fmt) in formats:
l1 = len(seen)
seen.add(fmt)
if l1 != len(seen):
process(value, fmt)
您的问题假定in
测试是一项代价高昂的操作。事实证明并非如此。使用len()
可能需要更多时间,尽管两者都非常快;
In [4]: seen = set(range(10000))
In [5]: %timeit 5995 in seen
10000000 loops, best of 3: 122 ns per loop
In [6]: %timeit len(seen)
1000000 loops, best of 3: 167 ns per loop
(在2.5 GHz Core Quad Q9300上使用CPython 2.7.3测量)
答案 1 :(得分:1)
我认为你的第一种方法是最好的。即使来自itertools recipes
的unique_everseen
食谱也使用相同的方法。
def unique_everseen(iterable, key=None):
"List unique elements, preserving order. Remember all elements ever seen."
# unique_everseen('AAAABBBCCDAABBB') --> A B C D
# unique_everseen('ABBCcAD', str.lower) --> A B C D
seen = set()
seen_add = seen.add
if key is None:
for element in ifilterfalse(seen.__contains__, iterable):
seen_add(element)
yield element
else:
for element in iterable:
k = key(element)
if k not in seen:
seen_add(k)
yield element
答案 2 :(得分:0)
你必须使用一套:
for (value, fmt) in set(formats):
process(value, fmt)
答案 3 :(得分:0)
from ordereddict import OrderedDict
unique_formats = list(OrderedDict.fromkeys(format))
process(unique_formats)
这将保留订单并删除重复项
答案 4 :(得分:0)
您可以使用itertools.groupby
按对的第二个元素进行分组,然后只考虑第一个值。
>>> from itertools import imap, groupby
>>> from operator import itemgetter
>>> formats = [(1, 'xxx'), (2, 'xxx'), (3, 'yyy'), (4, 'yyy')]
>>> for fmt, value in imap(lambda (x, y): (x, next(y)[0]), groupby(formats, itemgetter(1)):
... print('%s: %s', fmt, value)
...
xxx: 1
yyy: 3
答案 5 :(得分:0)
如果您的清单符合规定,您可以确保相同的格式彼此相邻。这意味着您无需使用集合来跟踪过去的值。只需使用一个变量来记录最后处理的格式:
last = None
for (value, fmt) in formats:
if fmt != last:
last = fmt
process(value, fmt)