【问题标题】:How to get the index of an integer from a list if the list contains a boolean?如果列表包含布尔值,如何从列表中获取整数的索引?
【发布时间】:2015-08-30 19:50:33
【问题描述】:

我刚开始使用 Python。

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

>>> lst = [True, False, 1, 3]
>>> lst.index(1)
0
>>> lst.index(True)
0
>>> lst.index(0)
1

我认为 Python 在index 方法的参数中将0 视为False1 视为True。如何获取整数1(即2)的索引?

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

【问题讨论】:

  • 从“这就是我想做的事……”来解决这个问题比“这是我不想做的事……”更好。例如您想要在列表中搜索某事物,但想要跳过与您正在搜索的事物比较相等的事物,您想要做什么具体?最可能的现实情况是,您确实希望 list.index(1) 尽管您感到惊讶但返回 0,或者您真的不应该将自己置于需要进行此搜索的情况。
  • 我不是 python 开发人员,但是将整数和布尔值一起存储在同一个列表中是不是有点奇怪?我认为它是将汽车和水果放在一起......

标签: python list indexing


【解决方案1】:

documentation 这么说

列表是可变序列,通常用于存储 同质项目(其中精确的相似程度会因 应用程序)。

您不应将异构数据存储在列表中。 list.index 的实现仅使用Py_EQ== 运算符)执行比较。在您的情况下,比较返回真实值,因为 TrueFalse 分别具有整数 1 和 0 的值(毕竟是 the bool class is a subclass of int)。

但是,您可以像这样使用生成器表达式和 built-in next function(从生成器中获取第一个值):

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

这里我们检查x是否是bool的实例之前比较x和1。

请记住,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

【讨论】:

    【解决方案2】:

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

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

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

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

    这里还有一个想法,你可以如何实现你想要的(但是,尝试重新考虑你的逻辑考虑到上面的信息):

    >>> 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方法中的元素,忽略布尔值。

    【讨论】:

      【解决方案3】:

      这是一个使用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

      【讨论】:

        【解决方案4】:

        试试这个。

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

        输出:

        2
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2019-09-24
          • 1970-01-01
          • 2019-02-09
          相关资源
          最近更新 更多