使这个简单的/ if块更加pythonic

时间:2014-05-17 00:38:19

标签: python

我需要在列表中存储超过给定最大限制的3个列表中的那些值的索引。这就是我得到的:

# Data lists.
a = [3,4,5,12,6,8,78,5,6]
b = [6,4,1,2,8,784,43,6,2]
c = [8,4,32,6,1,7,2,9,23]

# Maximum limit.
max_limit = 20.

# Store indexes in list.
indexes = []
for i, a_elem in enumerate(a):
    if a_elem > max_limit or b[i] > max_limit or c[i] > max_limit:
        indexes.append(i)

这有效,但我觉得很难看。我怎样才能让它更优雅/ pythonic?

5 个答案:

答案 0 :(得分:6)

您可以将for循环替换为:

indexes = []
for i, triplet in enumerate(zip(a, b, c)):
    if any(e > max_limit for e in triplet):
        indexes.append(i)

...你可以然后减少到列表理解:

indexes = [i for i, t in enumerate(zip(a, b, c)) if any(e > max_limit for e in t)]

...虽然这对我来说似乎有点笨拙 - 这真的是关于个人品味,但我更喜欢保持listcomps简单;在我看来,三行for循环更清晰。

正如user2357112所指出的,您可以使用max()降低列表理解的明显复杂性:

indexes = [i for i, t in enumerate(zip(a, b, c)) if max(t) > max_limit]

...虽然这不会像any()版本(和你自己的代码)一样短路,但可能会稍微慢一些。

答案 1 :(得分:2)

你可以尝试

if max(a_elem, b[i], c[i]) > max_limit:
    indexes.append(i)

这里的逻辑是找出这三个值中的任何一个是否需要大于max_limit。如果这三个元素中的最大元素大于max_limit,则满足您的条件。

答案 2 :(得分:2)

>>> maximums = map(max, zip(a, b, c))
>>> [i for i, num in enumerate(maximums) if num > max_limit]
[2, 5, 6, 8]

旧答案

以前,我在下面发布了这个烂摊子。上面的列表comp更易于管理。

>>> next(zip(*filter(lambda i: i[1] > max_limit, enumerate(map(max, zip(a, b, c))))))
(2, 5, 6, 8)

答案 3 :(得分:2)

我最喜欢exceeders =

import collections

# Data lists.
a = [3,4,5,12,6,8,78,5,6]
b = [6,4,1,2,8,784,43,6,2]
c = [8,4,32,6,1,7,2,9,23]

Triad = collections.namedtuple('Triad', 'a b c')
triads = [Triad(*args) for args in zip(a, b, c)]

triads = [t for t in zip(a, b, c)]  # if you don't need namedtuple

# Maximum limit.
max_limit = 20.

# Store indexes in list.
indexes = [for i, t in enumerate(triads) if max(t) > max_limit]
print indexes

# store the bad triads themselves in a list for
# greater pythonic

exceeders = [t for t in triads if max(t) > max_limit]
print exceeder

正如我上面评论的那样,使用并行数组来表示相关的数据会使简单的代码变得不那么简单。

在回复评论时添加了

也许我给了你太多的选择,所以我只会给出一种方法。所有答案的共同特点是它们融合了单独的数据列表和#34;使用zip输入行:

triads = [t for t in zip(a, b, c)]
exceeders = [t for t in triads if max(t) > max_limit]

它是:两行。重要的一点是,将任何内容的索引存储在列表中是一种C风格的处理方式,并且您要求使用Pythonic方式。保留索引列表意味着只要您想对该索引处的数据执行某些操作,就必须执行间接操作。执行这两行后,exceeders的值为:

[(5, 1, 32), (8, 784, 7), (78, 43, 2), (6, 2, 23)]

列表中的每个成员都有"列"发现超出限制的三个数据行。

现在你可能会说"但我真的想要指数而不是#34;。如果是这样,你的问题的另一部分你没有向我们展示哪些也依赖于列表索引。如果是这样,你仍然在用C / C ++ / Java方式做事,并且" Pythonic"将保持回避。

答案 4 :(得分:1)

m = lambda l: [i for i, e in enumerate(l) if e>max_limit]
indexes = sorted(set(m(a) + m(b) + m(c)))