以递归方式删除列表中的相邻重复项

时间:2014-03-26 19:59:04

标签: python recursion

我查了一下并找到了一个接近的例子,但是在这个链接中找到了答案:Remove adjacent duplicate elements from a list没有为这个问题运行测试用例。所以这就是我到目前为止所做的一切:

def remove_dups(thelist):
    """Returns: a COPY of thelist with adjacent duplicates removed.

    Example: for thelist = [1,2,2,3,3,3,4,5,1,1,1],
    the answer is [1,2,3,4,5,1]

    Precondition: thelist is a list of ints"""
    i = 1
    if len(thelist) == 0:
        return []
    elif len(thelist) == 1:
        return thelist
    elif thelist[i] == thelist[i-1]:
        del thelist[i]
    return remove_dups(thelist[i:])


def test_remove_dups():
    assert_equals([], remove_dups([]))
    assert_equals([3], remove_dups([3,3]))
    assert_equals([4], remove_dups([4]))
    assert_equals([5], remove_dups([5, 5]))
    assert_equals([1,2,3,4,5,1], remove_dups([1,2,2,3,3,3,4,5,1,1,1]))

# test for whether the code is really returning a copy of the original list
    mylist = [3]
    assert_equals(False, mylist is remove_dups(mylist))

编辑,虽然我明白上面使用itertools.groupby链接的接受的答案是可行的,但我认为它不能教会我的代码和错误是什么?如果我从itertools输入grouby,那将会破坏练习的目的。

4 个答案:

答案 0 :(得分:1)

from itertools import groupby

def remove_dups(lst):
    return [k for k,items in groupby(lst)]

如果你真的想要一个递归解决方案,我建议像

def remove_dups(lst):
    if lst:
        firstval = lst[0]

        # find lowest index of val != firstval
        for index, value in enumerate(lst):
            if value != firstval:
                return [firstval] + remove_dups(lst[index:])

        # no such value found
        return [firstval]
    else:
        # empty list
        return []

答案 1 :(得分:0)

你的断言失败了,因为在

return thelist

您将返回相同的列表,而不是评论中指定的副本。

尝试:

return thelist[:]

答案 2 :(得分:0)

当使用带有列表的递归时,大多数情况下返回子列表或该列表的一部分的问题。这使终止案例测试为空列表。然后你有两个案例:

  1. 当前值与我们看到的最后一个值不同,所以我们要保留它
  2. 当前值与我们看到的最后一个值相同,因此我们将其丢弃并继续迭代值的“其余”。
  3. 此代码中的哪个翻译:

    l = [1,2,2,3,3,3,4,5,1,1,1]
    
    def dedup(values, uniq):
      # The list of values is empty our work here is done
      if not values:
        return uniq
      # We add a value in 'uniq' for two reasons:
      #  1/ it is empty and we need to start somewhere
      #  2/ it is different from the last value that was added
      if not uniq or values[0] != uniq[-1]:
        uniq.append(values.pop(0))
        return dedup(values, uniq)
      # We just added the exact same value so we remove it from 'values' and 
      # move to the next iteration
      return dedup(values[1:], uniq)
    
    print dedup(l, []) # output: [1, 2, 3, 4, 5, 1]
    

答案 3 :(得分:0)

问题在于你的退货声明,

你要回来了

return remove_dups(thelist[i:])

输出将始终是列表

的单个元素 很快,就像上面一样,

print remove_dups([1,2,2,3,3,3,4,5,1,1,1])
>>> [1] #as your desired is [1,2,3,4,5,1]

最后返回单个元素的列表,因为它不考虑Oth元素。

这是递归解决方案。

def remove_dups(lst):
    if len(lst)>1:

        if lst[0] != lst[1]:
            return [lst[0]] + remove_dups(lst[1:])

        del lst[1]
        return remove_dups(lst)
    else:
        return lst