【问题标题】:How to sort generator type in python如何在python中对生成器类型进行排序
【发布时间】:2016-06-10 08:22:59
【问题描述】:

我的代码有以下几行

get_alarm_list = conn.query_alarms(query.filter_expr,
                                   query.orderb) 
print "type is:", type(get_alarm_list)
for alarm in get_alarm_list:
    if alarm.severity == 'critical':
        alarm.severity = 2
    elif alarm.severity == 'moderate':
        alarm.severity = 1
    else:
        alarm.severity = 0

alarm_list = sorted(get_alarm_list),
                    key=lambda a: a.severity,
                    reverse=True)
return [alarms.Alarm.from_db_model(alarm)
        for alarm in alarm_list]

输出:

type is <type 'generator'>

列表中的对象是:

for alarm in get_alarm_list:
     print alarm

Output:
<aodh.storage.models.Alarm object at 0x7fa4c0cb1c50>
<aodh.storage.models.Alarm object at 0x7fa4c0cb17d0>
<aodh.storage.models.Alarm object at 0x7fa4c0d86f10>
<aodh.storage.models.Alarm object at 0x7fa4ca372110>
<aodh.storage.models.Alarm object at 0x7fa4ca372190>
<aodh.storage.models.Alarm object at 0x7fa4c0c55d90>

每个警报由以下数据组成

 {'alarm_actions': [u'log://'], 'ok_actions': [], 'description': u'instance running hot', 'state': u'insufficient data', 'fields': ['alarm_actions', 'ok_actions', 'severity', 'timestamp', 'description', 'time_constraints', 'enabled', 'state_timestamp', 'rule', 'alarm_id', 'state', 'insufficient_data_actions', 'repeat_actions', 'user_id', 'project_id', 'type', 'name'], 'repeat_actions': False, 'enabled': True, 'state_timestamp': datetime.datetime(2016, 5, 27, 6, 41, 5, 987428), 'rule': {u'meter_name': u'cpu_util', u'evaluation_periods': 3, u'period': 600, u'statistic': u'avg', u'threshold': 70.0, u'query': [], u'comparison_operator': u'gt', u'exclude_outliers': False}, 'name': u'ddd', 'alarm_id': u'f5045ed5-5c53-4a6e-be53-23d3368f40c6', 'time_constraints': [], 'insufficient_data_actions': [], 'timestamp': datetime.datetime(2016, 5, 27, 6, 41, 5, 987428), 'user_id': u'9a65b258b5a24e74ac5feae2f6c54229', 'project_id': u'28d1c27e782c4448bf53da00f49d3e1b', 'type': u'threshold', 'severity': 2}

如何迭代生成器?

alarm_list = sorted(get_alarm_list,
                    key=lambda a: a.severity,
                    reverse=True)

但是这里alarm_list 是空的。我如何在生成器get_alarm_list上使用排序功能@

【问题讨论】:

  • sorted 适用于生成器。它将返回一个排序列表。你能发布足够的代码来重现你的问题吗?
  • @khelwood 我已经编辑了我的问题并发布了更多代码作为您的建议。
  • 在第 2 版中,您可以使用 for index, value in enumerate(get_alarm_list) 并将 get_alarm_list 更新为 get_alarm_list[index],因此您无需创建单独的列表...
  • 问题是您首先迭代get_alarm_list,因此消耗了该生成器,并且对sorted(get_alarm_list) 的以下调用导致一个空列表,因为get_alarm_list 没有更多元素。

标签: python sorting generator


【解决方案1】:

您的代码中的问题是您正在尝试对耗尽的生成器进行排序(您在for 循环思想生成器之后进行排序)。您可以对生成器对象产生的结果进行排序,因此您可以选择将生成器耗尽到变量中,换句话说,基于get_alarm_list 创建新列表为list(generator),然后使用简单的sorted 函数或@ 对其进行迭代和排序987654328@方法:

get_alarm_list = conn.query_alarms(query.filter_expr, query.orderb) 
sorted_alarm_list = sorted(list(get_alarm_list),
                               key=lambda a: a.severity,
                               reverse=True)
for alarm in sorted_alarm_list:
    print alarm

注意 1list(get_alarm_list) 执行后 - get_alarm_list 生成器变为空。而唯一存储conn.query_alarms 结果的项目是sorted_get_alarm_list。您可以在 Generators Python WikiUnderstanding Generators in Python 上阅读有关生成器的更多信息

注意 2:实际上,您可以将生成器对象传递给 sorted,并且您将获得与传递 list(generator) 相同的列表,但是如果您将列表传递给 sorted,则它的工作速度更快(请参阅更多关于 SO 回答 sorted() using Generator Expressions Rather Than Lists)。

【讨论】:

  • 基本上我在我的代码中尝试过的类似于for alarm in get_alarm_list: if alarm.severity == 2, alarm_list.append(alarm)。在这里我在修改内容ob 对象后附加了一个列表alarm_list。对吗?
  • 我按照您的建议尝试了list(get_alarm_list)。但它是空的。 print list(get_alarm_list) 。输出为[]
  • 是的,因为第一次执行 list(get_alarm_list) 后生成器为空。
  • 感谢您的详细解释。我使用了一个列表,我在修改严重性后将警报对象附加到它。然后我将此列表传递给排序方法。你觉得这样做可以吗?
  • 你的笔记得到了正确的答案,但我认为你真的应该改变你的第一句话。说你不能对生成器进行排序是完全错误的。
【解决方案2】:

您遇到的问题是,当您修改对象的 severity 属性时,您正在使用 for 循环中的整个生成器。这意味着当您调用 sorted 时,没有什么可迭代的了,因为生成器只适合一种用途。

您可以通过摆脱第一个循环并将严重性转换逻辑放入 key lambda 函数来解决此问题:

alarms_gen = conn.query_alarms(query.filter_expr, query.orderb) 
alarms_list = sorted(alarms_gen,
                     key=lambda x: {'critical': -2, 'moderate': -1}.get(x.severity, 0))

请注意,我已重命名您的 get_alarms_list 变量以减少误导(它不是列表)。我还通过将较高的优先级映射到负键值,使排序调用中不需要reverse=True

【讨论】:

  • 非常简洁,完美运行。这样,对象的严重性值将被保留,而不是转换为整数。 +1
  • 与其使用容易错过和混淆的-2-1,为什么不使用reverse=True
  • @NicHartley:这可行。您还可以使用按您需要的方式排序的任何其他值,因此您可以使用{'critical': 0, 'moderate': 1}.get(x.severity, 2)
猜你喜欢
  • 2016-06-01
  • 1970-01-01
  • 2013-11-03
  • 2011-10-21
  • 2020-09-18
  • 2020-10-09
  • 2017-12-20
  • 1970-01-01
  • 2020-02-23
相关资源
最近更新 更多