【问题标题】:List comprehension : Double loop WITH conditions列表理解:带条件的双循环
【发布时间】:2021-08-22 09:34:11
【问题描述】:

我尝试在 Python 3 中的列表理解方面训练自己,但我遇到了一个问题。 我在其他主题中看到了双循环语法,但在第二个循环中从来没有条件。

所以,我不得不说,在样本值和最大容量中,我能不能给一个样本充电。

我有一本字典 samples,其中包含样本的 id 及其 A/B/C 值。 我有一个 dict maximum 我可以充电的最大容量。 还有一个 samples_to_check 列表,其中包含我必须返回答案的样本。

samples_to_check = [0, 1, 2]

samples = {0: {"A": 2, "B": 0, "C": 3},
           1: {"A": 1, "B": 1, "C": 2},
           2: {"A": 0, "B": 0, "C": 5},
           3: {"A": 0, "B": 0, "C": 2}}

maximum = {"A": 2, "B": 2, "C": 2}

在这个例子中,我们只能对样本 1 收费,因为 A、B 和 C

result2 = [
    "CHARGE " + str(sample_id) for sample_id in samples_to_check
    if maximum["A"] - samples[sample_id]["A"] >= 0 and maximum["B"] - samples[sample_id]["B"] >= 0 and maximum["C"] - samples[sample_id]["C"] >= 0
]

print(result2)
['CHARGE 1']

但我想知道是否可以在不为每个字母重复相同条件的情况下找到最佳解决方案。

我试过这个,但它不起作用。

result = [
    "CHARGE " + str(sample_id) for sample_id in samples_to_check
    for letter in ["A", "B", "C"] if maximum[letter] - samples[sample_id][letter] >= 0
]

print(result)
['CHARGE 0', 'CHARGE 0', 'CHARGE 1', 'CHARGE 1', 'CHARGE 1', 'CHARGE 2', 'CHARGE 2']

谢谢。

【问题讨论】:

  • “正确”的形式是... if any(maximum[letter] - samples[sample_id][letter] >= 0 for letter in ["A", "B", "C"]]),但坦率地说,两者都不是特别可读。常规的for 循环或条件函数可能比将所有内容都塞进一个表达式中更好。

标签: python python-3.x performance optimization list-comprehension


【解决方案1】:

您可以使用 all/any 函数来检查所有字母的这种情况:

["charge {}".format(sample_id) for sample_id in samples_to_check if 
 all(maximum[key] - val >= 0  for key, val in samples[sample_id].items())]

但它的可读性不如我推荐的普通 for 循环。

for sample_id in samples_to_check:
    if all(maximum[key] - val >= 0  for key, val in samples[sample_id].items()):
        print('sample_id:', sample_id)

【讨论】:

  • 请注意,any/all 通常使用生成器表达式而不是列表推导效果更好,因为这样可以尽早退出而不是创建所有结果然后丢弃一些结果。 maximum[key] - val >= 0 也可以(更好?)写成 maximum[key] >= val
  • 当然可以!关于发电机,你是 100% 正确的!我什至不知道我为什么要放一个清单。关于条件 - 我想将其保留为 OP。
  • @Relandom 建议现在在 Python 中使用 f 字符串。 f"charge {sample_id}"
  • @blueteeth 是的,但是 OP 没有指定使用哪个版本的 python。
  • 非常感谢,正是我所需要的
【解决方案2】:

与@Relandom 非常相似,但格式略有不同。我认为列表推导比常规的 for 循环更简洁,并且创建了更多的 Python 代码。

在这里,我不是循环遍历samples_to_check,而是遍历主要数据,然后检查sample_id 是否需要检查,这对我来说更有意义。

[
    f"CHARGE {sample_id}"
    for sample_id, sample in samples.items()
    if (
        sample_id in samples_to_check
        and all(maximum[key] >= val for key, val in sample.items())
    )
]

【讨论】:

  • 这是一种极其浪费的方法——它具有 O(nm) 与初始 O(m) 运行时复杂性。它将不必要地查看不相关的samples,并一遍又一遍地查看samples_to_check 中的所有项目以查看sample_id 是否在其中。
  • 我明白你的意思。不过,这并不完全是非常浪费,尤其是在这种尺寸下。您可以将samples_to_check 设为一组。
猜你喜欢
  • 2022-01-12
  • 1970-01-01
  • 2016-05-29
  • 1970-01-01
  • 1970-01-01
  • 2022-11-07
  • 1970-01-01
  • 2017-12-09
相关资源
最近更新 更多