Python - 如果两个值在列表中出现两次,则在两个值的索引之间删除

Python - Remove between indexes of two values if it occurs twice in a list

标题肯定令人困惑,所以这里有一个例子:假设我有一个值列表 [1,2,3,2,1,4,5,6,7,8]。我想在列表中的两个 1 之间删除,并且通过 pythonic 方式它最终也会删除第一个 1 并输出 [1,4,5,6,7,8]。不幸的是,由于我缺乏 pythonic 能力,我只能产生一些删除第一组的东西:

a = [1,2,3,2,1,4,5,6,7]
uniques = []
junks = []
for value in a:
    junks.append(value)
    if value not in uniques:
        uniques.append(value)
for value in uniques:
    junks.remove(value)
for value in junks:
    a.remove(value)
    a.remove(value)
a[0] = 1
print(a)
[1,4,5,6,7]

适用于第一次出现两次,不适用于较大列表中的下一次出现。我有一个想法是在第一次出现的索引和第二次出现的索引之间删除,这将保留第二次出现,而不是让我做一些像 a[0] = 1 这样的愚蠢的事情,但我真的不确定如何实现它。

如果你想找到独特的元素,你可以使用 set 和 list

mylist = list(set(mylist))

这会按照你的要求做吗:

a = [1, 2, 3, 2, 1, 4, 5, 6, 7, 8]

def f(l):
    x = l.copy()
    for i in l:
        if x.count(i) > 1:
            first_index = x.index(i)
            second_index = x.index(i, first_index + 1)
            x = x[:first_index] + x[second_index:]
    return x

所以 f(a) 的输出将是 [1, 4, 5, 6, 7, 8]f([1, 2, 3, 2, 1, 4, 5, 6, 7, 8, 7, 6, 5, 15, 16]) 的输出将是 [1, 4, 5, 15, 16].

a = [1, 2, 3, 2, 1, 4, 5, 6, 7, 8, 7, 6, 5, 15, 16]
dup = [x for x in a if a.count(x) > 1] # list of duplicates
while dup:
    pos1 = a.index(dup[0])
    pos2 = a.index(dup[0], pos1+1)
    a = a[:pos1]+a[pos2:]
    dup = [x for x in a if a.count(x) > 1]
print a #[1, 4, 5, 15, 16]

更有效的解决方案是

a = [1, 2, 3, 2, 1, 4, 5, 6, 7, 8, 7, 6, 5, 15, 16]
pos1 = 0
while pos1 < len(a):
    if a[pos1] in a[pos1+1:]:
        pos2 = a.index(a[pos1], pos1+1)
        a = a[:pos1]+a[pos2:]
    pos1 += 1
print a #[1, 4, 5, 15, 16]

(这可能不是最有效的方法,但希望它有所帮助)

你不能只检查是否有东西出现两次,如果有,你有 firstIndex,secondIndex,然后:

a=[1,2,3,4,5,1,7,8,9]
b=[]

#do a method to get the first and second index of the repeated number then

for index in range(0, len(a)):
    print index
    if index>firstIndex and index<secondIndex: 
        print "We removed: "+ str(a[index])

    else:
        b.append(a[index])         

print b

输出是[1,1,7,8,9],这似乎是你想要的。

完成你需要的工作:

  • 重复值的第一个和最后一个位置
  • 之间的所有索引,删除它们

有趣的是,你可以简单地告诉 python 这样做:

# we can use a 'smart' dictionary, that can construct default value:
from collections import defaultdict

# and 'chain' to flatten lists (ranges)
from itertools import chain

a = [1, 2, 3, 2, 1, 4, 5, 6, 7]

# build dictionary where each number is key, and value is list of positions:
index = defaultdict(list)
for i, item in enumerate(a):
    index[item].append(i)

# let's take first only and last index for non-single values
edges = ((pos[0], pos[-1]) for pos in index.values() if len(pos) > 1)

# we can use range() to get us all index positions in-between
# ...use chain.from_iterable to flatten our list
# ...and make set of it for faster lookup:
to_remove = set(chain.from_iterable(range(start, end) 
                for start, end in edges))
result = [item for i, item in enumerate(a) if i not in to_remove]
# expected: [1, 4, 5, 6, 7]
print result

当然你可以缩短它:

index = defaultdict(list)
for i, item in enumerate([1, 2, 3, 2, 1, 4, 5, 6, 7]):
    index[item].append(i)
to_remove = set(chain.from_iterable(range(pos[0], pos[-1]) 
                    for pos in index.values() if len(pos) > 1))
print [item for i, item in enumerate(a) if i not in to_remove]

此解决方案具有线性复杂度,应该非常快。成本是 字典和集合的额外内存,所以你应该小心巨大的数据集。但是如果你有很多数据,其他使用 lst.index 的解决方案无论如何都会窒息,因为它们是 O(n^2) 并且有很多解引用和函数调用。