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) 并且有很多解引用和函数调用。
标题肯定令人困惑,所以这里有一个例子:假设我有一个值列表 [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) 并且有很多解引用和函数调用。