有条件地从两个列表中选择元素的巧妙方法?

时间:2014-03-06 05:14:22

标签: python list

我有两个清单:

a = [-1, 2, 3]
b = ['a', 'b', 'c']

ab中的元素数量始终相同。

我希望a中的所有元素都是正数,以及b的相应元素。

一种直截了当的方式是

anew = []
bnew = []
for i in xrange(len(a)):
    if a[i] > 0:
         anew.append(a[i])
         bnew.append(b[i])

或类似

tmp = zip(*[(a[i], b[i]) for i in xrange(len(a)) if a[i]>0])
a = tmp[0] # The original a and b need not to be kept.
b = tmp[1]

我想知道是否有更短更清洁(没有任何临时变量)的方法。某种就地删除会很完美,但如果我在循环中使用del a[i], b[i],删除一个元素后索引就会出错。

编辑:如果选择涉及两个列表,例如条件变为

,该怎么办?

if a[i] > 0 and b[i] > 0

也许在这种情况下必须使用临时变量?

6 个答案:

答案 0 :(得分:6)

如果您使用numpy,则有一种非常巧妙的方式:

In [117]: a = np.array([-1, 2, 3])
     ...: b = np.array(['a', 'b', 'c'])

In [119]: a[a>0]
Out[119]: array([2, 3])

In [120]: b[a>0]
Out[120]: 
array(['b', 'c'], 
      dtype='|S1')

如果没有numpy,您可以将列表理解与条件语句一起使用:

In [121]: a = [-1, 2, 3]
     ...: b = ['a', 'b', 'c']

In [122]: print [i for i in a if i>0]
[2, 3]

In [124]: print [v for i, v in enumerate(b) if a[i]>0]
['b', 'c']

答案 1 :(得分:2)

我认为它可能是最短的:

filter(lambda x:x[0]>0, zip(a,b))

答案 2 :(得分:1)

您可以使用“zip-filter-unzip”策略:

说明步骤:

>>> [(aa, bb) for aa, bb in zip(a, b) if aa > 0]
[(2, 'b'), (3, 'c')]
>>> zip(*[(aa, bb) for aa, bb in zip(a, b) if aa > 0])
[(2, 3), ('b', 'c')]

最终结果:

>>> aaa, bbb = zip(*[(aa, bb) for aa, bb in zip(a, b) if aa > 0])
>>> aaa
(2, 3)
>>> bbb
('b', 'c')

正如你所看到的,我给了你一对元组 - 不是一对列表。在许多应用程序中,这并不重要,但如果确实如此,转换并不太困难; - )

这也扩展到两个列表都需要大于0的元素的情况:

aaa, bbb = zip(*[(aa, bb) for aa, bb in zip(a,b) if aa > 0 and bb > 0])

答案 3 :(得分:0)

你可以分两步完成。它不是“短”但绝对简单和干净。

b = [b[i] for i in xrange(len(b)) if a[i] > 0]
a = [x for x in a if x > 0]

答案 4 :(得分:0)

一些功能工具可以在一行中完成,非常好。:

anew, bnew = map(lambda x: list(x), zip(*filter(lambda z: z[0] > 0, zip(a, b))))

答案 5 :(得分:0)

如果元素的顺序对您无关紧要,那么您可以将最后一个元素与当前元素交换为负数。以下是我的想法的代码。

l = len(a)
i = 0
while i < l:
    print i,l
    while a[i] < 0:
        a[i] = a[-1]
        b[i] = b[-1]
        a.pop()
        b.pop()
        global l
        l = len(a)
    i = i+1


print a
print b