快速过滤元组列表

时间:2017-12-05 22:18:16

标签: python list

如何根据第一项是否与第三项相同来有效地使用Python过滤元组列表?

假设我有old_data,我想要new_data:

old_data = [(2,3,2), (3,4,4), (7,6,7), (2,1,2), (5,7,2)]

new_data = [(3,4,4), (5,7,2)]

我目前的解决方案(列表理解)太慢了:

new_data_too_slow = [x for x in old_data if x[0] != x[2]]

这个数据是数百万行,我需要以相同的格式返回元组列表。

2 个答案:

答案 0 :(得分:2)

我不确定你是如何使用你的数据的(这很重要!)但是更改为生成器可能会提升性能。

您需要做的就是将[更改为(

new_data_too_slow = (x for x in old_data if x[0] != x[2])

同样,这取决于你如何使用它,但这种方法很容易胜过大多数IO操作。另外,因为它是一个生成器,你可以使用它 - 但你会使用更少的内存。

答案 1 :(得分:0)

这可以使用numpy有效地完成,因为它的操作是用C编码的。

In [16]: import numpy as np

In [17]: old_data = [(2,3,2), (3,4,4), (7,6,7), (2,1,2), (5,7,2)]

In [18]: np_data = np.asarray(old_data)

In [19]: new_data = np_data[ np_data[:,0] != np_data[:,2 ] ]

In [20]: new_data
Out[20]: array([[3, 4, 4],
                [5, 7, 2]])

第一和第三项的比较将以这种方式更快。转换为numpy并不一定是昂贵的,因为np.asarray(而不仅仅是np.array)不会复制原始数据,除非它必须,它只是包装它。

此时new_data是一个numpy数组,您可以迭代它,就像它是一个元组列表一样,但是您可以轻松地将其转换为列表列表。 ..

In [22]: new_data.tolist()
Out[22]: [[3, 4, 4], [5, 7, 2]]

...然后进入具有列表解析的元组列表中,如果它确实对您的目的是必要的。

以下是一些生成数据的比较部分的时序,其中包含一百万行,所有元素都为0或1。

In [58]: test_data = np.random.randint( 0, 2, size=(1000000,3) )

In [59]: test_data
Out[59]: 
array([[1, 1, 0],
       [1, 0, 0],
       [0, 1, 0],
       ..., 
       [0, 0, 1],
       [0, 1, 0],
       [0, 1, 1]])

In [60]: %%timeit                                              
new_data = test_data[test_data[:,0] != test_data[:,2]]
   ....: 
10 loops, best of 3: 26.2 ms per loop

In [61]: test_data = test_data.tolist()                   

In [62]: %%timeit                                               
new_data = [ x for x in test_data if x[0] != x[2] ]
   ....: 
1 loop, best of 3: 345 ms per loop