【问题标题】:Make this faster. (Min, Max in same iteration using a condition)让这更快。 (使用条件的同一迭代中的最小值、最大值)
【发布时间】:2015-06-25 17:09:38
【问题描述】:

我想问一下我是否/如何重写下面的这些行,以更快地运行。

*(-10000, 10000) 只是我可以确定我的数字介于两者之间的范围。

    first = 10000
    last = -10000

    for key in my_data.keys():
        if "LastFirst_" in key:  # In my_data there are many more keys with lots of vals.
            first = min(first, min(my_data[key]))
            last = max(last, max(my_data[key]))

    print first, last

另外,是否有任何 Python 方式来编写它(即使这并不意味着它会运行得更快)?

谢谢

【问题讨论】:

  • 真的应该在 Code Review 上。
  • 您可以使用float("inf")float("-inf") 作为您的最小值和最大值。

标签: python for-loop iteration max min


【解决方案1】:

使用* 运算符解压缩值:

>>> my_data = {'LastFirst_1':[1, 4, 5], 'LastFirst_2':[2, 4, 6]}
>>> d = [item for k,v in my_data.items() if 'LastFirst_' in k for item in v]
>>> first = 2
>>> last = 5
>>> min(first, *d)
1
>>> max(last, *d)
6

【讨论】:

  • 当我们只是在寻找第一个和最后一个时,使用哈希集是不是有点矫枉过正?
  • 除非包含的数据类型不可散列,否则sets 在这里是理想的,因为我们不关心重复,sets 速度很快。
  • sets 可以快速进行会员测试,但这似乎并没有发挥作用。要计算minmax,无论如何都必须迭代整个列表。
  • 将每个元素放入哈希表是有代价的。它很聪明,但既不比使用列表和生成器更具表现力,也更高效。使用哈希有什么好处?
  • 如果我没看错你的意图,你可以简化你的 d 分配:d = set(el for k,v in my_data.items() if 'LastFirst_' in k for el in v)
【解决方案2】:

您可以使用一些推导来简化代码。

first = min(min(data) for (key, data) in my_data.items() if "LastFirst_" in key)
last = max(max(data) for (key, data) in my_data.items() if "LastFirst_" in key)

【讨论】:

  • 这需要在键中检查“LastFirst_”的次数是两倍。
  • 是的。但是OP不介意。 “(即使这并不意味着它会运行得更快)”
  • 对不起,大脑跳过了最后一句话。第一句话要求更快。
  • 不包括初始的 firstlast 值。
  • @TigerhawkT3:不需要。 “(-10000, 10000) 只是我可以确定我的数字介于两者之间的范围。”
【解决方案3】:

minmax 函数被重载以获取多个值(当您使用它时)或一个值序列,因此您可以传入可迭代对象(例如列表)并获取它们的最小值或最大值.

另外,如果您只对值感兴趣,请使用.values()itervalues()。如果您对两者都感兴趣,请使用.items().iteritems()。 (在 Python 3 中,没有.iter- 版本。)

如果你有很多序列,你可以使用itertools.chain 使它们成为一个长可迭代的。您也可以在单个理解中使用多个 for 手动将它们串起来,但这可能会令人反感。

import itertools

def flatten1(iterables):
    # The "list" is necessary, because we want to use this twice
    # but `chain` returns an iterator, which can only be used once.
    return list(itertools.chain(*iterables))

# Note: The "(" ")" indicates that this is an iterator, not a list.
valid_lists = (v for k,v in my_data.iteritems() if "LastFirst_" in k)
valid_values = flatten1(valid_lists)
# Alternative: [w for w in v for k,v in my_data.iteritems() if "LastFirst_" in k]  

first = min(valid_values)
last = max(valid_values)

print first, last

如果最大和最小元素不在字典中,那么编码人员应该决定做什么,但我建议他们考虑允许max/min 的默认行为(可能是引发的异常,或None 值),而不是尝试猜测上限或下限。任何一个都会更 Pythonic。

在 Python 3 中,您可以指定 default 参数,例如max(valid_values, default=10000).

【讨论】:

  • 这似乎比递归答案更快,因为它只检查一次密钥。
  • 但不包括最初的 firstlast
  • 不过,您假设最小和最大元素在字典中。
  • @Markon,我添加了它们,但只是删除了它们。将添加我的理由。
【解决方案4】:
my_data = {'LastFirst_a': [1, 2, 34000], 'LastFirst_b': [-12000, 1, 5]}

first = 10000
last = -10000

# Note: replace .items() with .iteritems() if you're using Python 2.
relevant_data = [el for k, v in my_data.items() for el in v if "LastFirst_" in k]
# maybe faster:
# relevant_data = [el for k, v in my_data.items() for el in v if k.startswith("LastFirst_")]

first = max(first, max(relevant_data))
last = min(last, min(relevant_data))

print(first, last)

【讨论】:

  • 您错误地使用了*max()。这将导致错误。
  • max() 返回单个值,因此解包不起作用。
  • 现在我看到了:relevant_datalistlists,所以你在其中找到了最大/最小 list,然后找到了这些的最大/最小和first/last。这可能会产生奇怪的结果,因为似乎 list 比较是基于第一个元素评估的(即,[4,1] > [3]True[1,4] > [3]False)。
  • 我明白了。我现在先把列表弄平了,应该可以更好地概括。
【解决方案5】:
values = [my_data[k] for k in my_data if 'LastKey_' in k]
flattened = [item for sublist in values for item in sublist]
min(first, min(flattened))
max(last, max(flattened))

values = [item for sublist in (j for a, j in d.iteritems() if 'LastKey_' in a) for item in sublist]
min(first, min(values))
max(last, max(values))

我正在运行一些基准测试,似乎第二种解决方案比第一种解决方案稍快。 不过,我也将这两个版本与其他发帖者发布的代码进行了比较。

solution one:  0.648876905441
solution two:  0.634277105331
solution three (TigerhawkT3):  2.14495801926
solution four (Def_Os):  1.07884407043
solution five (leewangzhong):  0.635314941406

基于随机生成的包含 100 万个键的字典。 我觉得李旺中的解决方案真的很好。除了上面显示的时间之外,在接下来的实验中,它的结果比我的第二个解决方案略快(不过我们谈论的是毫秒),例如:

solution one:  0.678879022598
solution two:  0.62641787529
solution three:  2.15943193436
solution four:  1.05863213539
solution five:  0.611482858658

Itertools 真的是一个很棒的模块!

【讨论】:

  • 这似乎不包括"LastFirst_" in key 条件。
  • 如果键中的“LastFirst_”:'怎么样?
  • 调用my_data[k] 是不必要的密钥查找。应该使用itemsiteritems
  • 您测试的是我的set 解决方案还是我当前的解决方案?
  • 您当前的。由于反复拆包,我猜它看起来有点慢......
猜你喜欢
  • 2015-04-03
  • 2016-07-13
  • 2012-09-30
  • 1970-01-01
  • 1970-01-01
  • 2017-01-27
  • 1970-01-01
  • 1970-01-01
  • 2020-12-15
相关资源
最近更新 更多