3

我有一个要处理的有序列表,其中包括一些重复项,我只想处理第一次出现。目前,我在 Python v2.7 中这样做:

seen = set()
for (value, fmt) in formats:
  if fmt not in seen:
    seen.add(fmt)
    process(value, fmt)

无论如何要同时插入一个新元素seen并检测它是否已经存在?(这样可以避免在 . 中重复查找fmtset

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)
4

6 回答 6

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 测量)

于 2013-04-04T19:37:06.803 回答
1

我认为你的第一种方法是最好的。甚至unique_everseen来自的配方itertools recipes也使用相同的方法。

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
于 2013-04-04T19:51:16.440 回答
0

您必须使用一组:

for (value, fmt) in set(formats):
   process(value, fmt)
于 2013-04-04T19:34:09.210 回答
0
from ordereddict import OrderedDict
unique_formats = list(OrderedDict.fromkeys(format))
process(unique_formats)

这将保留订单并删除重复项

于 2013-04-04T19:47:48.657 回答
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
于 2013-04-04T19:53:33.140 回答
0

如果您的列表是有序的,您可以确定相同的格式将彼此相邻。这意味着您不需要使用集合来跟踪过去的值。只需使用一个变量来记录最后处理的格式:

last = None
for (value, fmt) in formats:
    if fmt != last:
        last = fmt
        process(value, fmt)
于 2013-04-04T19:59:22.420 回答