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

Cap*_*row 14 python indexing list

我刚开始使用Python.

1如果列表包含一个布尔True对象之前,如何从列表中获取整数索引1

>>> lst = [True, False, 1, 3]
>>> lst.index(1)
0
>>> lst.index(True)
0
>>> lst.index(0)
1
Run Code Online (Sandbox Code Playgroud)

我认为Python认为,0作为False1作为True在的参数index方法.如何获得整数索引1(即2)?

另外,在列表中以这种方式处理布尔对象背后的原因或逻辑是什么?从解决方案来看,我可以看到它并不那么简单.

vau*_*tah 13

文件说,

列表是可变序列,通常用于存储同类项目的集合(其中精确的相似程度将根据应用而变化).

您不应将异构数据存储在列表中.实现list.index仅使用Py_EQ(==运算符)执行比较.在你的情况下,比较返回truthy值,因为True并且分别False具有整数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
Run Code Online (Sandbox Code Playgroud)

在这里,我们检查是否x是比较1 bool 之前的实例x.

请记住,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
Run Code Online (Sandbox Code Playgroud)

一些例子:

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
Run Code Online (Sandbox Code Playgroud)


Rom*_*huk 8

布尔值 Python 中的整数,这就是为什么你可以像任何整数一样使用它们:

>>> 1 + True
2
>>> [1][False]
1
Run Code Online (Sandbox Code Playgroud)

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

这是因为它bool是一个子类int,并且几乎总是布尔值的行为就像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
Run Code Online (Sandbox Code Playgroud)

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


Jam*_*lls 5

这是一个非常简单的天真单线解决方案,使用mapzip:

>>> zip(map(type, lst), lst).index((int, 1))
2
Run Code Online (Sandbox Code Playgroud)

在这里,我们映射每个元素的类型,并通过使用元素压缩类型并请求索引来创建新列表(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
Run Code Online (Sandbox Code Playgroud)

在这里,我们基本上做了相同的事情,但迭代地,以便在内存/空间效率方面不花费我们太多.我们同样的表情从以上,但使用迭代器imapizip而不是和构建返回迭代器或养的下一个值的自定义函数索引ValueError,如果没有匹配.