【问题标题】:Find first sequence item that matches a criterion [duplicate]查找与标准匹配的第一个序列项[重复]
【发布时间】:2012-04-09 18:02:18
【问题描述】:

查找/返回符合特定标准的第一个列表项的最优雅、最有效的方法是什么?

例如,如果我有一个对象列表,我想获取属性为obj.val==5 的对象中的第一个对象。我当然可以使用列表推导,但这会产生 O(n) 并且如果 n 很大,那就是浪费。一旦满足条件,我也可以使用带有break 的循环,但我认为可能会有更pythonic/优雅的解决方案。

【问题讨论】:

  • 如果要获取item和index怎么办?
  • @CharlieParker, 要同时获取索引和项目,请使用 enumerate() - next((idx, obj) for idx, obj in enumerate(objs) if obj.val==5)

标签: python list


【解决方案1】:

如果您的对象没有任何其他索引或排序信息,那么您将不得不迭代直到找到这样的对象:

next(obj for obj in objs if obj.val == 5)

然而,这比完整的列表理解要快。比较这两个:

[i for i in xrange(100000) if i == 1000][0]

next(i for i in xrange(100000) if i == 1000)

第一个需要 5.75ms,第二个需要 58.3µs(快 100 倍,因为循环短了 100 倍)。

【讨论】:

  • next 还提供了一个 default 参数,以防不存在对象。例如。 next((i for i in range(500) if i > 600), 600) 将返回 600。
  • Python next()
  • 嗯,就是这样,但我只是希望正确的答案看起来更酷。我们总是宣传 python 如此优雅。如果你想让它变得健壮,你应该提供default(例如None)——然后你不要忘记Generator expression must be parenthesized if not sole argument...嗯,这对可读性有什么影响?例如。第一个非路径参数:next((arg for arg in sys.argv if not os.path.exists(arg)), None) - 不是很友好。
  • 是的。如果它让你感到厌烦,你总是可以做def first(items, pred): return next((i for i in items if pred(i)), None)
  • 如果你也想找到项目和索引怎么办?
【解决方案2】:
a = [100, 200, 300, 400, 500]

def search(b):
 try:
  k = a.index(b)
  return a[k] 
 except ValueError:
    return 'not found'

print(search(500))

如果找到它会返回对象,否则它会返回“未找到”

【讨论】:

  • 这很好,但仅在标准是与列表项的比较时才有效。我一直在寻找一种更通用的解决方案来处理更广泛的选择
  • 但@Jonathan 在您的问题中提到了查找\返回第一个列表项的有效方法,因此上述列表 a=[100,200,300,400,500] 可以包含任何类型的对象,而不仅仅是数字。
  • 我用“...匹配某个标准”来结束这句话,这与匹配平等或身份不同:) 我做了+1,因为我认为你的解决方案很好对于平等\身份私人案例
猜你喜欢
  • 2012-01-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-01-07
相关资源
最近更新 更多