5

给定一个布尔列表,例如[True, False, False, True, False, True],获取包含原始列表中的 Truthy 元素的索引(从 1 开始,而不是零索引)的列表/元组的最快方法是什么?所以对于上面的列表,它应该返回[1, 4, 6]or (1, 4, 6)

我正在使用这样的生成器:

def get_truthy_ones(self, bool_list):
    return (idx + 1 for idx, value in enumerate(bool_list) if value)

但是,当我想将结果编码到JSON对象中时,这会产生问题,因为JSON不编码生成器。

4

4 回答 4

12
[i for i, elem in enumerate(bool_list, 1) if elem]
于 2012-10-25T20:17:44.553 回答
3

将括号切换为方括号以返回列表而不是生成器:

def get_truthy_ones(self, bool_list):
    return [idx for idx, value in enumerate(bool_list, 1) if value]

或者使用您的原始函数,然后从生成器创建一个列表:

list(get_truthy_ones(self, bool_list))
于 2012-10-25T20:18:34.860 回答
2

正因为它可以做到,一个替代版本与itertools.compress(). 我认为这比其他示例可读性差,所以我不推荐它。

>>> list(itertools.compress(*zip(*enumerate([True, False, False, True, False, True], 1))))
[1, 4, 6]

编辑:

python -m timeit -s "import itertools" -s "values = [True, False]*10000" "list(itertools.compress(*zip(*enumerate(values, 1))))"
100 loops, best of 3: 2.88 msec per loop

python -m timeit -s "import itertools" -s "values = [True, False]*10000" "[index for index, value in enumerate(values, 1) if value]"
1000 loops, best of 3: 1.11 msec per loop

明显慢,其实,所以绝对不是一个用。

于 2012-10-25T20:24:09.833 回答
1

如果有办法将列表转换为 numpy 数组,使用 numpy.where() 应该更快:

> python -m timeit -s "import numpy" -s "values = numpy.array([True, False]*10000)" "numpy.where(values)"
1000 loops, best of 3: 392 usec per loop

> python -m timeit -s "import itertools" -s "values = [True, False]*10000" "[index for index, value in enumerate(values, 1) if value]"
100 loops, best of 3: 2.1 msec per loop

但是我可能在这里通过在设置中进行转换来作弊。

于 2012-10-25T20:52:11.697 回答