有序集Python 2.7

时间:2011-06-01 07:00:15

标签: python list set python-2.7

我有一个列表,我正在尝试从中删除重复的项目。我正在使用python 2.7.1,所以我可以简单地使用 set()函数。但是,这会重新排序我的列表。对于我的具体情况,这是不可接受的。

下面是我写的一个函数;这样做。但是我想知道是否有更好/更快的方式。对此也有任何意见,将不胜感激。

    def ordered_set(list_):

        newlist = []
        lastitem = None
        for item in list_:

            if item != lastitem:
                newlist.append(item)
                lastitem = item

        return newlist

上述功能假设所有项目都不是,并且项目是有序的(即 ['a','a','a',' b','b','c','d']

上述函数返回 ['a','a','a','b','b','c','d'] ['a ','b','c','d']

8 个答案:

答案 0 :(得分:12)

使用set的另一种非常快速的方法:

def remove_duplicates(lst):
    dset = set()
    # relies on the fact that dset.add() always returns None.
    return [item for item in lst
            if item not in dset and not dset.add(item)] 

答案 1 :(得分:8)

使用OrderedDict:

from collections import OrderedDict

l = ['a', 'a', 'a', 'b', 'b', 'c', 'd']
d = OrderedDict()

for x in l:
    d[x] = True

# prints a b c d
for x in d:
    print x,
print

答案 2 :(得分:7)

假设输入序列是无序的,这里是O(N)解决方案(空间和时间)。 它会生成一个删除了重复项的序列,同时保留与输入序列中出现的相同顺序的唯一项。

>>> def remove_dups_stable(s):
...   seen = set()
...   for i in s:
...     if i not in seen:
...       yield i
...       seen.add(i)

>>> list(remove_dups_stable(['q', 'w', 'e', 'r', 'q', 'w', 'y', 'u', 'i', 't', 'e', 'p', 't', 'y', 'e']))
['q', 'w', 'e', 'r', 'y', 'u', 'i', 't', 'p']

答案 3 :(得分:5)

我知道这已经得到了解答,但这里有一个单行(加上导入):

from collections import OrderedDict
def dedupe(_list):
    return OrderedDict((item,None) for item in _list).keys()

>>> dedupe(['q', 'w', 'e', 'r', 'q', 'w', 'y', 'u', 'i', 't', 'e', 'p', 't', 'y', 'e'])
['q', 'w', 'e', 'r', 'y', 'u', 'i', 't', 'p']

答案 4 :(得分:3)

我认为这完全没问题。你获得的O(n)表现是你所希望的最佳表现。

如果列表无序,那么您需要一个帮助器set来包含您已经访问过的项目,但在您的情况下则没有必要。

答案 5 :(得分:2)

如果您的列表没有排序,那么您的问题没有意义。 例如[1,2,1]可以成为[1,2]或[2,1]

如果您的列表很大,您可能希望使用SLICE将结果写回同一列表以节省内存

>>> x=['a', 'a', 'a', 'b', 'b', 'c', 'd']
>>> x[:]=[x[i] for i in range(len(x)) if i==0 or x[i]!=x[i-1]]
>>> x
['a', 'b', 'c', 'd']

有关内联删除的信息,请参阅Remove items from a list while iteratingRemove items from a list while iterating without using extra memory in Python

你可以使用的一个技巧是,如果你知道x被排序,你知道x [i] = x [i + j]那么你不需要检查x [i]和x [i +]之间的任何东西j](如果您不需要删除这些j值,您只需将所需的值复制到新列表中)

因此,如果集合中的所有内容都是唯一的,那么你就无法击败n次操作,即len(set(x))= len(x) 可能有一种算法将n比较作为最坏的情况,但可以将n / 2比较作为最佳情况(或者如果你知道某种方式事先知道len(x)/ len,那么它的最佳情况就是n / 2; set(x))> 2,因为您生成的数据):

最佳算法可能会使用二分搜索来找到分而治之类型方法中每个最小i的最大值j。初始除法可能是长度len(x)/近似(len(set(x)))。希望它可以执行,即使len(x)= len(set(x))它仍然只使用n次操作。

答案 6 :(得分:2)

中描述了unique_everseen解决方案 http://docs.python.org/2/library/itertools.html

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

答案 7 :(得分:0)

对我来说没问题。如果你真的想使用集合做这样的事情:

def ordered_set (_list) :
    result = set()
    lastitem = None
    for item in _list :
        if item != lastitem :
            result.add(item)
            lastitem = item
    return sorted(tuple(result))

我不知道你会得到什么表现,你应该测试一下;可能是因为方法过热而一样!

如果你真的是偏执狂,就像我一样,请在这里阅读:

http://wiki.python.org/moin/HowTo/Sorting/

http://wiki.python.org/moin/PythonSpeed/PerformanceTips

记得这个(它包含答案):

http://www.peterbe.com/plog/uniqifiers-benchmark