【问题标题】:Get value at list/array index or "None" if out of range in Python如果在 Python 中超出范围,则在列表/数组索引处获取值或“无”
【发布时间】:2012-08-24 13:29:47
【问题描述】:

是否有干净的方法来获取列表索引或None(如果索引超出或在 Python 中的范围)处的值?

这样做的明显方法是:

if len(the_list) > i:
    return the_list[i]
else:
    return None

但是,冗长会降低代码的可读性。有没有一种干净、简单的单线可以代替?

【问题讨论】:

标签: python


【解决方案1】:

试试:

try:
    return the_list[i]
except IndexError:
    return None

或者,一个班轮:

l[i] if i < len(l) else None

例子:

>>> l=list(range(5))
>>> i=6
>>> print(l[i] if i < len(l) else None)
None
>>> i=2
>>> print(l[i] if i < len(l) else None)
2

【讨论】:

  • 这有一个不幸的副作用,即使用异常作为控制流,而他的原始版本已经没有,而且这也不是很冗长。
  • @DanielDiPaolo:在 python 中,鼓励以这种方式使用异常,而不是不赞成。
  • @BrtH:关于 LBYL(在你跳跃之前查看(if 语句))人群和 EAFP(更容易请求宽恕而不是许可(尝试/除外))人群有两种思想流派。 ..但是一般来说,以这种方式使用异常绝对不会不受欢迎......但我认为这在很大程度上取决于个人喜好
  • 我怀疑异常流会像简单的 if-else 一样高效。
  • 除了在 Python 异常流程中 性能更高:异常在 Python 中是非常轻量级的,并且仅在出现异常时才会产生(有限的)开销发生。 if 语句意味着在代码无论如何都会执行时运行比较。检查this answerthis doc
【解决方案2】:
return the_list[i] if len(the_list) > i else None

【讨论】:

  • @JoranBeasley 单行语句怎么比各种多行语句更冗长?
  • @semicolon 另一个不好的指标。
【解决方案3】:

出于您的目的,您可以排除 else 部分,因为如果不满足给定条件,则默认返回 None

def return_ele(x, i):
    if len(x) > i: return x[i]

结果

>>> x = [2,3,4]
>>> b = return_ele(x, 2)
>>> b
4
>>> b = return_ele(x, 5)
>>> b
>>> type(b)
<type 'NoneType'>

【讨论】:

    【解决方案4】:

    我发现列表切片对此很有用:

    >>> x = [1, 2, 3]
    >>> a = x [1:2]
    >>> a
    [2]
    >>> b = x [4:5]
    >>> b
    []
    

    因此,如果您想要 x[i],请始终访问 x[i:i+1]。如果存在,您将获得一个包含所需元素的列表。否则,您会得到一个空列表。

    【讨论】:

    • 附录:可以扩展为my_list[idx: idx+1] or "Default_value"。可读性强! :)
    • 这应该是一个可以接受的答案,因为它可以避免 if 并使用空列表。它也适用于由列表理解创建的列表:a = [1,3,5,7,9]; b = [num for num in a if num % 2 == 0][0:1] or "No evens found"; print(b) No evens found
    • @Erich Nice 但它会产生一个列表,而不是一个值。所以满满的一个班轮会看起来很丑:(my_list[idx: idx+1] or ["Default_value"])[0]
    • @SergeyNudnov 我同意你的解决方案。它有点毛茸茸,但最干净的方式是作为单线。我会说,在这一点上,它可能需要在个人库中使用一个小的帮助函数
    【解决方案5】:

    如果您正在处理小列表,则不需要添加 if 语句或类似的东西。一个简单的解决方案是将列表转换为字典。然后你可以使用dict.get:

    table = dict(enumerate(the_list))
    return table.get(i)
    

    您甚至可以使用dict.get 的第二个参数设置除None 之外的另一个默认值。例如,如果索引超出范围,则使用table.get(i, 'unknown') 返回'unknown'

    请注意,此方法不适用于负索引。

    【讨论】:

      【解决方案6】:

      结合切片和迭代

      next(iter(the_list[i:i+1]), None)
      

      【讨论】:

      • 读者注意:我可以解释这个答案的唯一方法是它是一个笑话。您永远不应该将其用作 OP 问题中问题的解决方案。
      【解决方案7】:

      1.如果...否则...

      l = [1, 2, 3, 4, 5]
      for i, current in enumerate(l):
          following = l[i + 1] if i + 1 < len(l) else None
          print(current, following)
      # 1 2
      # 2 3
      # 3 4
      # 4 5
      # 5 None
      

      2。试试……除了……

      l = [1, 2, 3, 4, 5]
      for i, current in enumerate(l):
          try:
              following = l[i + 1]
          except IndexError:
              following = None
          print(current, following)
      # 1 2
      # 2 3
      # 3 4
      # 4 5
      # 5 None
      

      3.字典

      适合小单子

      l = [1, 2, 3, 4, 5]
      dl = dict(enumerate(l))
      for i, current in enumerate(l):
          following = dl.get(i + 1)
          print(current, following)
      # 1 2
      # 2 3
      # 3 4
      # 4 5
      # 5 None
      

      4.列表切片

      l = [1, 2, 3, 4, 5]
      for i, current in enumerate(l):
          following = next(iter(l[i + 1:i + 2]), None)
          print(current, following)
      # 1 2
      # 2 3
      # 3 4
      # 4 5
      # 5 None
      

      5. itertools.zip_longest

      from itertools import zip_longest
      
      l = [1, 2, 3, 4, 5]
      for i, (current, following) in enumerate(zip_longest(l, l[1:])):
          print(current, following)
      # 1 2
      # 2 3
      # 3 4
      # 4 5
      # 5 None
      

      使用%%timeit的Jupyter魔术命令

      初始化

      from itertools import zip_longest
      
      l = list(range(10000000))
      

      结果

      Method Consume
      if...else... 2.62 s
      try...except... 1.14 s
      dict 2.61 s
      List slicing 3.75 s
      itertools.zip_longest 1.14 s

      【讨论】:

      • 感谢您提供几个场景 + 对它们进行基准测试。一个非常有见地的答案!
      猜你喜欢
      • 2023-03-16
      • 1970-01-01
      • 1970-01-01
      • 2017-07-03
      • 1970-01-01
      • 1970-01-01
      • 2018-08-18
      • 2015-01-18
      • 1970-01-01
      相关资源
      最近更新 更多