不使用`in`或`set`关键字从有序列表中删除重复值

时间:2014-07-20 12:11:52

标签: python list

我正在尝试从有序列表中删除重复值而不使用IN或SET关键字

我有以下代码,它删除第一次出现重复值,但不删除第二个重复值

def remove_duplicates(list1):
    new_list = list(list1)
    indx = 0
    while indx+1 < len(new_list):
        if new_list[indx] == new_list[indx+1] :
             new_list.pop(indx)
        indx += 1
    return new_list

有一个重复它可以工作:

>>> remove_duplicates([1,2,3,3,4])
[1,2,3,4]

但没有三个重复:

>>> remove_duplicates([1,2,3,3,3,4])
[1,2,3,3,4]

据我所知,当您从列表中弹出值时,它也会减小1的大小

任何建议。

7 个答案:

答案 0 :(得分:4)

您可以使用filter功能:

>>>uniq = {}
>>>filter(lambda x:uniq.update({x:1}),[1,2,3,3,3,4])
>>> print uniq.keys()
[1, 2, 3, 4]

答案 1 :(得分:3)

使用字典键

>>> dict.fromkeys(lst).keys()
[1, 2, 3, 5]

诀窍是,字典只允许使用唯一键,因此使用具有重复键名的名称创建字典会导致只有一组唯一键。

有值列表:

>>> lst = [1, 1, 1, 2, 3, 3, 5]

我们使用列表值作为键创建一个词典:

>>> dct = dict.fromkeys(lst)
>>> dct
{1: None, 2: None, 3: None, 5: None}

由于所有的关键名称只能出现在:

>>> dct.keys()
[1, 2, 3, 5]

我们有所需要的。

>>> dict.fromkeys(lst).keys()
[1, 2, 3, 5]

我必须承认,即使它没有使用set,使用dict密钥也是非常相似的方法。

答案 2 :(得分:2)

使用生成器

>>> def remove_duplicates(iterable):
...     last_val = iterable.next()
...     yield last_val
...     for itm in iterable:
...         if itm != last_val:
...             last_val = itm
...             yield last_val
...
>>> lst = [1, 1, 1, 2, 3, 3, 5]
>>> list(remove_duplicates(iter(lst)))
[1, 2, 3, 5]

生成器逐个产生值。

在循环开始之前产生初始值。

remove_duplicates需要一个可迭代的,因此如果传递一个,则调用需要调用iter(lst) 名单。另一种选择是在发电机内部进行,但我的决定是这样做 外部。

list in:

list(remove_duplicates(iter(lst)))

是强制生成器产生所有值。

答案 3 :(得分:2)

使用groupby

简而言之:

>>> from itertools import groupby
>>> lst = [1, 1, 1, 2, 3, 3, 5]
>>> map(lambda grpitm: grpitm[0], groupby(lst))
[1, 2, 3, 5]

一步一步:

>>> from itertools import groupby
>>> lst = [1, 1, 1, 2, 3, 3, 5]
>>> list(groupby, lst)
[(1, <itertools._grouper at 0x7f759f976a90>),
 (2, <itertools._grouper at 0x7f759f976ad0>),
 (3, <itertools._grouper at 0x7f759f976b10>),
 (5, <itertools._grouper at 0x7f759f976b50>)]

groupby返回一个迭代器,它产生元组(groupname,grouitemiterator)。

对于我们的任务,我们只关心groupname:

>>> map(lambda grpitm: grpitm[0], groupby(lst))

这将从groupby返回每个元组,并从中选择第一个元素。

请注意,在Pyhton 3.x中,您必须将map放入list才能看到值:

>>> list(map(lambda grpitm: grpitm[0], groupby(lst)))

答案 4 :(得分:1)

轮到我试图解决那个有趣的&#34; Sunday Python拼图&#34;

>>> def remove_duplicates(lst):
...     result = [x for x,n in zip(lst,lst[1:]+[lst[0:1]]) if x != n]
...     return result if result or not lst else lst[0:1]
... 
>>> lst = [1, 1, 1, 2, 3, 3, 5]
>>> print remove_duplicates(lst)
[1, 2, 3, 5]
>>> 
>>> lst = [5, 5]
>>> print remove_duplicates(lst)
[5]
>>> 
>>> lst = [5]
>>> print remove_duplicates(lst)
[5]
>>> 
>>> lst = []
>>> print remove_duplicates(lst)
[]

此答案具有保存原始列表顺序的属性。

有人可能会说我应该使用itertools.izip。她/他可能是对的。但是,嘿,它的星期天....所以让我们假装我使用Python 3。

答案 5 :(得分:0)

试试这个:

def remove_duplicates(list1):
    new_list = list(list1)
    indx = 0
    while indx+1 < len(new_list):
        if new_list[indx] == new_list[indx+1] :
            new_list.pop(indx)
        else:
            indx += 1
    return new_list

现在的方式,如果你检测到副本作为三元组的一部分,它将删除中间元素,然后将索引前进到最后一个元素。然后,第一个和最后一个永远不会被比较。这种方式只有在没有检测到重复的情况下才会增加索引。

答案 6 :(得分:0)

我认为这个“星期日拼图游戏”的答案数量没有限制,这是我的第二次尝试。事实上,它应该是第一个,因为这个谜题是reduce的完美候选者。我不知道我怎么能错过这么久。但是,嘿,现在还是星期天...

>>> def remove_duplicates(lst):
...     return reduce(lambda x,n: (x + [n]) if [n] != x[-1:] else x, lst, [])
... 
>>> lst = [1, 1, 1, 2, 3, 3, 5]
>>> print remove_duplicates(lst)
[1, 2, 3, 5]
>>> 
>>> lst = [5, 5]
>>> print remove_duplicates(lst)
[5]
>>> 
>>> lst = [5]
>>> print remove_duplicates(lst)
[5]
>>> 
>>> lst = []
>>> print remove_duplicates(lst)
[]