有序集Python 2.7

有序集Python 2.7,python,list,set,python-2.7,Python,List,Set,Python 2.7,我有一个试图从中删除重复项的列表。我使用的是python 2.7.1,因此我可以简单地使用set()函数。然而,这将重新排列我的列表。这对我来说是不可接受的 下面是我写的一个函数;这就是为什么。但是我想知道是否有更好/更快的方法。如有任何意见,将不胜感激 def ordered_set(list_): newlist = [] lastitem = None for item in list_: if item

我有一个试图从中删除重复项的列表。我使用的是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
上述函数假定所有项都不是none,并且这些项都是有序的(即,['a','a','a','b','b','c','d']


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

我认为这完全可以。你得到了最好的表现

如果列表是无序的,那么您需要一个助手
set
来包含您已经访问过的项目,但在您的情况下,这不是必需的。

使用有序的信息:

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

我觉得还可以。如果确实要使用集合,请执行以下操作:

def ordered_set (_list) :
    result = set()
    lastitem = None
    for item in _list :
        if item != lastitem :
            result.add(item)
            lastitem = item
    return sorted(tuple(result))
我不知道你会得到什么样的表现,你应该测试一下;可能是相同的,因为方法过热

如果你真的像我一样多疑,请阅读这里:

刚刚记住这一点(其中包含答案):


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

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

>>> 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']
有关内联删除,请参见或

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

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


在分治式方法中,最优算法可能会使用二进制搜索为每个最小i找到最大j。初始分段的长度可能为len(x)/近似值(len(set(x)))。希望它能够被执行,即使len(x)=len(set(x)),它仍然只使用n个操作。

另一种非常快速的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)] 

假设输入序列是无序的,下面是
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']

我知道这个问题已经得到了回答,但这里有一行(加上进口):


中描述了一种独特的解决方案


这就要求元素通过散列;例如,如果元素是列表或字典,这将不起作用;此外,这需要一个
O(n)
操作,而不是一堆
O(1)
操作(这可能不是OP想要的,也可能不是OP需要记住的),我以前从未见过被描述为“一堆O(1)操作”的for循环。嗯,没有(1)项行动将是。。。O(n)我认为这与将4描述为2+2是一样的。但是如果列表很大呢?保存这些额外的True将耗费大量内存。我真的不明白python为什么没有有序集。默认情况下保持插入顺序有什么问题?这只是一个很好的额外财产!还有一个类似的问题给出了一个实现的链接,是否最好让列表自动保持排序并且不重复?或者必须定期清除重复列表可以吗?您的示例代码暗示
\u list
是一个只有连续重复的序列。这就是你的意思吗?对于像这样的输入,
[1,2,-4,-4,1]
1
仍将重复,而
-4
将消除重复。您测试了代码吗?您从未将任何内容分配给
结果
。另外,集合的全部要点是,您不需要检查它是否已经包含元素-您只需要
result=set(\u list)
。不需要迭代。但是,如果项目的顺序不是字母顺序,则此方法(或您的方法)将失败…尝试使用此函数的任何人都将获得:NameError:未定义全局名称“newlist”为什么要向下投票?我认为Tim Pietzckers post没有错。谢谢你的补充,Pavel。[2,1,2,1]可能会变成[1,2]或[2,1],我同意[2,1]在这种情况下更有意义,但问题中没有暗示。如果集合是有序的,那么您的解决方案仍然是好的,所以+1@robert,也可以对@zaur的解决方案进行投票,因为它也使用列表理解做完全相同的事情。回想起来,我更喜欢这一个,因为它看起来代码更少:)哎呀@罗伯特,我没注意时间顺序。注意:)谢谢。是的@zaur的解决方案很好,但是如果元素不能被散列,它将失败。(如果列表没有排序,我们都会失败)。我认为我的解决方案可能是最快的,但还没有在占用我全部内存的大型阵列上使用=)
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']
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