关于python:为什么我在使用这段代码时没有更改列表?

Why I get the list unchanged when using this code?

我希望使用此结构来延迟列表中的重复元素,但使用此代码时列表保持不变。有人能帮我吗?

例如,item=[1,2,3,4,5,6,7,8,9,1,2,6,7]

1
2
3
4
5
6
7
8
9
10
def duplicated(item):
        i=0
        j=0
        while i<len(item):
                while j<len(item):
                        if item[j]==item[i] and i!=j:
                                del item[j]
                        j+=1
                i+=1
        return item


为了解决代码不工作的原因,这是因为您在函数开始时初始化了j,所以在i循环的第一次迭代之后,它是len(item)-1,然后再也不会为将来的循环重置。

这意味着你错过了许多副本。

所以,既然我们需要在每个循环中初始化它,我们仍然需要知道该怎么做。如果我们将其初始化为0,那么我们将检查列表中当前j值后面的重复项,这样做是浪费时间。为了提高效率,我们应该将其初始化为i+1,以便我们检查i后面的数字是否有重复项,因为我们已经知道列表中索引i之前i处的值没有重复项。这也简化了if,因为我们不再需要检查i != j

最后一件事是,当使用del删除j时,后面的所有索引现在都向下移动了一个。因此,我们还需要从j中减去1,这样我们就可以直接检查刚刚删除的元素之后的元素,它现在与刚刚删除的元素索引相同(因为它们被下移)。

所以,在代码中:

1
2
3
4
5
6
7
8
9
10
11
def duplicated(item):
        i = 0
        while i < len(item):
                j = i + 1
                while j < len(item):
                        if item[j] == item[i]:
                                del item[j]
                                j -= 1
                        j += 1
                i += 1
        return item

它与人们给出的例子一起工作:

1
2
3
4
>>> duplicated([1,2,3,4,5,6,7,8,9,1,2,6,7])
[1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> duplicated([1,2,3,4,5,6,7,8,9,1,1,2,6,7])
[1, 2, 3, 4, 5, 6, 7, 8, 9]

但是,由于我们使用的是嵌套循环,所以所用的时间与输入列表的平方大小成正比,因此该解决方案是目前的O(n^2)复杂性解决方案。

但是,如果我们能够将算法修改为只使用一个循环,我们将把复杂性降低到O(n)。这可以通过使用查找集来完成。添加和检查集合中的元素是否是EDOCX1(平均大小写21),这样我们就可以使用它们来加快速度。

因此,如果我们有一个集合包含我们已经看到的元素,那么对于每个未来的元素,如果它已经在seen集合中,我们删除它,否则我们将它添加到这个集合中。

所以,在代码中:

1
2
3
4
5
6
7
8
9
10
def duplicated(item):
    seen = set()
    i = 0
    while i < len(item):
        if item[i] in seen:
            del item[i]
        else:
            seen.add(item[i])
            i += 1
    return item

我可以确认这也通过了上面的测试用例。

我要指出的最后一点是,在这里删除元素时,我没有从指针中减去,这是因为在我们减去之前,我们知道它稍后会增加,我们希望它是相同的,但是在这里,它只在else块中增加,所以如果我们不做任何事情,它将保持不变。


实际上,变量j应该从i选择的下一项开始。

1
2
3
4
5
6
7
8
9
10
11
def duplicated(item):
    i=0
    while i<len(item):
        j = i+1
        while j<len(item):
            if item[j]==item[i] and i!=j:
                del item[j]
                j -= 1
            j+=1
        i+=1
    return item


每次嵌套while循环开始时需要重新初始化j:

1
2
3
4
5
6
7
8
9
10
11
12
def duplicated(item):
        i=0
        j=0
        while i<len(item)-1:
            j=i+1
            while j<len(item):
                    if item[j]==item[i]:
                            del item[j]
                            j -= 1
                    j+=1
            i+=1
        return item

。出

1
[1, 2, 3, 4, 5, 6, 7, 8, 9]

但是,您可以尝试以下更简单的代码,它将保持列表的插入顺序

1
2
3
4
5
6
def duplicated(item):
    unique_list=[]
    for i in item:
        if i not in unique_list:
            unique_list.append(i)
    return unique_list


你应该在i循环的每一圈重新初始化你的jvar,否则,在第一次迭代之后,j总是等于len(item)

1
2
3
4
5
6
7
8
9
10
11
def duplicated(item):
    i=0
    while i<len(item):
        j=0
        while j<len(item):
            if item[j]==item[i] and i!=j:
                print(i,j )
                del item[j]
            j+=1
        i+=1
    return item

但是,如果不关心列表顺序,最好的方法可能是将列表转换为一个集合,然后再转换回一个列表,有一个集合只能有不同的元素。

1
2
def duplicated(item):
    return list(set(item))