如何检查iterable的元素是否包含某些内容

时间:2020-05-24 21:30:01

标签: python python-3.x

我有一个多维可迭代的a,我需要找出a的哪些元素以b作为其第一运算符。现在,我使用[i for i in a if i[0] == b],但是如果a真的很长,那就太慢了。有更快或更简单的替代方法吗? 示例:a = [[5, 8], [6, 7], [5, 4], [8, 5]]b = 5,预期收益为[[5, 8], [5, 4]]

2 个答案:

答案 0 :(得分:1)

一种方法是使用numpy数组,例如:

In [21]: import numpy as np

In [22]: l = np.random.randint(1,10,size=(5000,2))

In [23]: %timeit [i for i in l if i[0] == 5]
1.9 ms ± 49.2 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

In [24]: %timeit l[l[:,0] == 5]
26.9 µs ± 60 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)

以及有关您的数据示例:

In [25]: a = np.array([[5, 8], [6, 7], [5, 4], [8, 5]])
    ...: b = 5

In [26]: a[a[:,0] == b]
Out[26]: 
array([[5, 8],
       [5, 4]])

答案 1 :(得分:1)

在一个未知长度的可迭代对象的一般情况下,我不知道一种更快的方法。问题的症结在于Python速度慢,因此检查每个可迭代项的第一项是否相等的最快方法是避免在Python中进行。根据数据的结构,这里有几种使用NumPy加速这些比较的方法(其内部是在C中实现的,而不是在Python中实现的。)

使用numpy数组

...如果所有内部可迭代对象的长度都相同,并且所有元素都是相同的类型。

例如,如果您有

some_list = [[1, 2, 3], [4, 5, 6], [7, 8, 9], [10, 11, 12]]

您可以将其格式化为numpy数组,然后执行np.array(some_list)[:, 0](或者,更好的做法是np.array(some_list, order="F")[0, :],因为numpy数组默认情况下具有主要行存储顺序)。

使用新的数据结构

...如果第一个元素具有特殊状态。

也许您可以创建一个新对象来容纳可迭代对象而不是列表。例如,代替

people_list = [['Bruce', 1, 2, 3], ['Sharon', 7, 3, 2, 3, 2], ['Lee', 3]]

您可以创建一个新对象

class People:
    def __init__(self, names, data):
        assert len(names) == len(data)
        self.names = np.asarray(names)  # A vector of names
        self.data = data

    def get_person_data_by_name(self, name):
        person_matches = np.where(self.names == names)[0]
        if len(person_matches) == 0:
            retrieved_data = None
        elif len(person_matches) == 1:
            retrieved_data = self.data[person_matches[0]]
        else:
            raise RuntimeError("Multiple people with that name.")

        return retrieved_data

people = People(['Bruce', 'Sharon', 'Lee'], [[1, 2, 3], [7, 3, 2, 7, 2], [3]])

这消除了所有可迭代项必须具有相同长度的限制,但对数据施加了其他限制。