从两个列表的相同索引位置同时移除多个元素

3

问题:

我有两个长列表,每个列表中大约有50,000个元素,并且它们的大小是完全相同的。列表a包含8个值(全部不同),后面跟着16个零,直到列表结尾,列表b是对第一个列表执行三角函数而得到的结果。

我想从列表a中删除所有的零,然后删除列表b中相应的索引。

示例(全部为1和2只是为了简单起见):

a = [1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2] ...

b = [1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,2,2] ...

成为

a = [1,1,1,1,1,1,1,1,2,2] ...

b = [1,1,1,1,1,1,1,1,2,2] ...

实际上,除了零之外,每个元素都有一个不同的值。因此,我考虑使用循环来扫描列表a寻找零,并从两个列表中删除该索引处的元素。
到目前为止,这是我想到的方法,但我收到了“列表索引超出范围”的错误提示。
for i in range(len(a)):
    if a[i] == 0:
        a.remove(a[i])
        b.remove(b[i])
    else:
        pass

谢谢


是的,它们有。列表'a'每24个元素具有重复结构。有8个值(全部不同,但在示例中我使用了'1'),后跟16个零。列表'b'在每个索引处都有一个值(这里我又使用了'1')。我放置'2'的地方表示第二次重复的开始。实际上,它会重复2000多次。关键是每个非零元素都具有完全不同的值,只有列表'a'中的零是一致和重复的。编辑:之前的评论已被删除,请忽略此内容。 - rh1990
4个回答

3

使用numpy高级索引功能,您只需几行代码即可完成:

import numpy as np
a = np.array(a)
b = np.array(b)[a != 0].tolist()
a = a[a != 0].tolist()

如果你正在处理大量数据,考虑使用numpy


谢谢,这个可行。我用numpy做很多事情,我会开始考虑在我的列表中使用它。 - rh1990

1
a = [1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2]
b = [1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,2,2]
x = zip(a,b)
x = filter(lambda item: item[0] != 0, x)
a,b = map(list,zip(*x))

使用zip来合并列表a和b,结果如下:

[(1, 1), (1, 1), (1, 1), (1, 1), (1, 1), (1, 1), (1, 1), (1, 1), (0, 1), (0, 1), (0, 1), (0, 1), (0, 1), (0, 1), (0, 1), (0, 1), (0, 1), (0, 1), (0, 1), (0, 1), (0, 1), (0, 1), (0, 1), (0, 1), (0, 1), (2, 2), (2, 2)]

然后过滤出第一个元素为0的tuple。 最后,解压缩结果并转换为list
在Python 3.0之前,如果有大量元素,建议使用itertools.izip。

1
一种方法是:
a = [1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2]
b = [1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,2,2]
new_a = []
new_b = []
for i,j in zip(a,b):
    if i:
        new_a.append(i)
        new_b.append(j)
a = new_a
b = new_b
print(a)
print(b)

它产生了什么。
[1, 1, 1, 1, 1, 1, 1, 1, 2, 2]
[1, 1, 1, 1, 1, 1, 1, 1, 2, 2]

使用相同的方法,但使用列表推导式可以更快地解决问题,代码如下:

new_a = [i for i in a if i]
b = [j for i,j in zip(a,b) if i]
a = new_a

注意:正如您所看到的,无需在每次迭代中使用索引或查找列表中的零元素。

0

我认为这是更好的去除零的方法:
解决方案1

while a.count(0):
     a.remove(0)

print a #[1,1,1,...,2]

或者你可以这样做: sol2

for i in range(len(a)-1,-1,-1):
      if a[i] == 0:
          a.remove(a[i])
          b.remove(b[i])

你的代码无法正常工作的原因是,当你从零开始并使用range(len(a))假设范围为25时,然后删除第四个元素,现在你的范围是24,你的列表不再有第25个元素!所以当你在for循环中,i等于24时,你会得到索引错误(因为此时你的列表较小),但如果你从列表末尾开始移动,当你的列表变小时,这个问题就不会发生。


@RichardHall:第二个正是你想要的! - Iman Mirzadeh
缩进不正确。最重要的是,它仍然必须在每次迭代中查找列表中的元素,这是不必要的。计时它。 - Pynchia
@Pynchia:缩进正确!这是O(n^2),我认为没有更好的解决方案!如果列表已排序,可能可以实现O(n*log(n))! - Iman Mirzadeh
是的,缩进现在是正确的。至于算法:正如我所建议的那样,计时它。我相信有更好的方法(请参见我的谦虚回答,但可能还有更好的方法)。 - Pynchia
@Pynchia sol2 稍微有些作用,虽然现在我有了两个与原始大小相同的列表,但所有结果都被推到前面,然后跟着成千上万个0。有没有一种方法可以完全删除索引位置并将所有内容向后移动?最终,我想要两个比以前短三分之一的列表(保留8个,删除16个)编辑:忽略那个,我把我的列表标签反了。这也可以,谢谢! - rh1990
显示剩余3条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接