如果列表包含布尔值,如何从列表中获取整数的索引?

17

我刚开始学习Python。

如果列表中在整数1之前存在一个布尔值True对象,如何获取该整数1的索引?

>>> lst = [True, False, 1, 3]
>>> lst.index(1)
0
>>> lst.index(True)
0
>>> lst.index(0)
1
我认为Python在index方法的参数中将0视为False,将1视为True。如何获取整数1(即2)的索引?
此外,在列表中处理布尔对象的逻辑或原因是什么?从解决方案中可以看出,这并不是那么简单明了的。

4
更好的方法是从“这是我想要做什么”的角度来解决问题,而不是“这是我不想做什么”的角度。例如,你具体想要做什么,即想在列表中搜索一个元素,但又想跳过与你正在搜索的元素相等的元素?情况的最有可能的现实是,你确实希望 list.index(1) 返回 0,尽管你感到惊讶,或者你真的不应该让自己陷入需要进行这种搜索的局面中。 - user1084944
6
我不是Python开发人员,但将整数和布尔值存储在同一列表中是否有点奇怪?我认为这就像将汽车和水果一起列出一样... - Laurent S.
4个回答

14

文档中指出:

列表是可变序列,通常用于存储同类数据的集合(具体相似程度因应用而异)。

您不应该在列表中存储异构数据。使用list.index时,实现仅使用Py_EQ==运算符)进行比较。在您的情况下,该比较返回真值,因为TrueFalse的值分别为整数1和0(毕竟bool类是int的子类)。

然而,您可以像这样使用生成器表达式和next内置函数(来获取生成器中的第一个值):

In [4]: next(i for i, x in enumerate(lst) if not isinstance(x, bool) and x == 1)
Out[4]: 2

在比较x和1之前,我们检查x是否为bool的实例。

请记住,next可能会引发StopIteration异常,在这种情况下,可能希望(重新)引发ValueError异常(以模仿list.index的行为)。

将所有内容封装到一个函数中:

def index_same_type(it, val):
    gen = (i for i, x in enumerate(it) if type(x) is type(val) and x == val)
    try:
        return next(gen)
    except StopIteration:
        raise ValueError('{!r} is not in iterable'.format(val)) from None

一些例子:

In [34]: index_same_type(lst, 1)
Out[34]: 2

In [35]: index_same_type(lst, True)
Out[35]: 0

In [37]: index_same_type(lst, 42)
ValueError: 42 is not in iterable

8

在Python中,布尔值整数,因此您可以像使用整数一样使用它们:

>>> 1 + True
2
>>> [1][False]
1

[这并不意味着你应该 :)]

这是因为boolint的一个子类,几乎总是布尔值的行为就像0或1一样(除非它被转换为字符串 - 你会得到"False""True")。

这里还有一个想法,你可以通过它实现你想要的效果(不过,请尝试重新思考你的逻辑,考虑以上信息):

>>> class force_int(int):
...     def __eq__(self, other):
...         return int(self) == other and not isinstance(other, bool)
... 
>>> force_int(1) == True
False
>>> lst.index(force_int(1))
2

这段代码重新定义了int类型的方法,用于在index方法中比较元素时忽略布尔值。

5

以下是一个使用 mapzip 的简单且朴素的一行式解决方案:

>>> zip(map(type, lst), lst).index((int, 1))
2

在这里,我们将每个元素的类型进行映射,并通过将类型与元素压缩在一起创建一个新列表,并请求(type, value)的索引。

以下是使用相同技术的通用迭代解决方案:

>>> from itertools import imap, izip
>>> def index(xs, x):
...     it = (i for i, (t, e) in enumerate(izip(imap(type, xs), xs)) if (t, e) == x)
...     try:
...             return next(it)
...     except StopIteration:
...             raise ValueError(x)
... 
>>> index(lst, (int, 1))
2

我们基本上做的是同样的事情,但是采用迭代的方式,以便在内存/空间效率方面不会花费太多。我们使用与上述相同的表达式的迭代器,但是使用 imapizip 并构建一个自定义索引函数,该函数返回迭代器中的下一个值,如果没有匹配,则抛出ValueError


0

试一下这个。

for i, j in enumerate([True, False, 1, 3]):
    if not isinstance(j, bool) and j == 1:
        print i

输出:

2

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