【问题标题】:Combinations from dictionary with list values using Python使用 Python 将字典与列表值组合
【发布时间】:2011-04-21 21:07:23
【问题描述】:

我有以下传入值:

variants = {
  "debug" : ["on", "off"],
  "locale" : ["de_DE", "en_US", "fr_FR"],
  ...
}

我想处理它们,所以我得到以下结果:

combinations = [
  [{"debug":"on"},{"locale":"de_DE"}],
  [{"debug":"on"},{"locale":"en_US"}],
  [{"debug":"on"},{"locale":"fr_FR"}],
  [{"debug":"off"},{"locale":"de_DE"}],
  [{"debug":"off"},{"locale":"en_US"}],
  [{"debug":"off"},{"locale":"fr_FR"}]
]

这应该适用于字典中任意长度的键。在 Python 中使用 itertools,但没有找到任何符合这些要求的东西。

【问题讨论】:

  • 你确定你不想有一个二元素字典的列表吗?

标签: python algorithm list dictionary combinations


【解决方案1】:
import itertools as it

varNames = sorted(variants)
combinations = [dict(zip(varNames, prod)) for prod in it.product(*(variants[varName] for varName in varNames))]

嗯,这会返回:

[{'debug': 'on', 'locale': 'de_DE'},
 {'debug': 'on', 'locale': 'en_US'},
 {'debug': 'on', 'locale': 'fr_FR'},
 {'debug': 'off', 'locale': 'de_DE'},
 {'debug': 'off', 'locale': 'en_US'},
 {'debug': 'off', 'locale': 'fr_FR'}]

这可能不是你想要的。让我适应它...

combinations = [ [ {varName: val} for varName, val in zip(varNames, prod) ] for prod in it.product(*(variants[varName] for varName in varNames))]

现在返回:

[[{'debug': 'on'}, {'locale': 'de_DE'}],
 [{'debug': 'on'}, {'locale': 'en_US'}],
 [{'debug': 'on'}, {'locale': 'fr_FR'}],
 [{'debug': 'off'}, {'locale': 'de_DE'}],
 [{'debug': 'off'}, {'locale': 'en_US'}],
 [{'debug': 'off'}, {'locale': 'fr_FR'}]]

瞧 ;-)

【讨论】:

  • 哇,这速度很快,正是我想要的。谢啦。有时询问比自己尝试几个小时要快得多。
  • 事实上,您的第一个解决方案对我来说更有用。只是对我的一个误解,要求您在第二个中构建一个:)
【解决方案2】:

我假设您想要所有键的笛卡尔积?因此,如果您有另一个条目“foo”,其值为 [1, 2, 3],那么您总共有 18 个条目?

首先,将值放在一个列表中,其中每个条目都是该位置的可能变体之一。在您的情况下,我们希望:

[[{'debug': 'on'}, {'debug': 'off'}], [{'locale': 'de_DE'}, {'locale': 'en_US'}, {'locale': 'fr_FR'}]]

这样做:

>>> stuff = []
>>> for k,v in variants.items():
    blah = []
    for i in v:
        blah.append({k:i})
    stuff.append(blah)


>>> stuff
[[{'debug': 'on'}, {'debug': 'off'}], [{'locale': 'de_DE'}, {'locale': 'en_US'}, {'locale': 'fr_FR'}]]

接下来我们可以使用笛卡尔积函数来扩展它...

>>> def cartesian_product(lists, previous_elements = []):
if len(lists) == 1:
    for elem in lists[0]:
        yield previous_elements + [elem, ]
else:
    for elem in lists[0]:
        for x in cartesian_product(lists[1:], previous_elements + [elem, ]):
            yield x


>>> list(cartesian_product(stuff))
[[{'debug': 'on'}, {'locale': 'de_DE'}], [{'debug': 'on'}, {'locale': 'en_US'}], [{'debug': 'on'}, {'locale': 'fr_FR'}], [{'debug': 'off'}, {'locale': 'de_DE'}], [{'debug': 'off'}, {'locale': 'en_US'}], [{'debug': 'off'}, {'locale': 'fr_FR'}]]

请注意,这不会复制字典,因此所有 {'debug': 'on'} 字典都是相同的。

【讨论】:

  • 有趣的是,所有这些代码都等同于之前的单行代码。很高兴知道 Cartesian_product 是内置的,我从来不知道!
  • itertools.product(以及组合和排列)是 python 2.6 中对 itertools 的一个很好的补充。但是,我不喜欢这个名字。正如您所写,它应该是“cartesian_product”,产品应该是可迭代元素的乘积:reduce(operator.mul, it)
  • 那么你总共有 18 个条目?是的:) 没有我想要的新名称。感谢您的提示。
【解决方案3】:
combinations = [[{key: value} for (key, value) in zip(variants, values)] 
                for values in itertools.product(*variants.values())]

[[{'debug': 'on'}, {'locale': 'de_DE'}],
 [{'debug': 'on'}, {'locale': 'en_US'}],
 [{'debug': 'on'}, {'locale': 'fr_FR'}],
 [{'debug': 'off'}, {'locale': 'de_DE'}],
 [{'debug': 'off'}, {'locale': 'en_US'}],
 [{'debug': 'off'}, {'locale': 'fr_FR'}]]

【讨论】:

    【解决方案4】:

    这是我用的:

    from itertools import product
    
    def dictproduct(dct):
        for t in product(*dct.itervalues()):
            yield dict(zip(dct.iterkeys(), t))
    

    适用于您的示例给出:

    >>> list(dictproduct({"debug":["on", "off"], "locale":["de_DE", "en_US", "fr_FR"]}))
    [{'debug': 'on', 'locale': 'de_DE'},
     {'debug': 'on', 'locale': 'en_US'},
     {'debug': 'on', 'locale': 'fr_FR'},
     {'debug': 'off', 'locale': 'de_DE'},
     {'debug': 'off', 'locale': 'en_US'},
     {'debug': 'off', 'locale': 'fr_FR'}]
    

    我发现这比上面的一行更具可读性。

    此外,它返回一个类似 itertools.product 的迭代器,因此它让用户决定是实例化一个列表还是一次只使用一个值。

    【讨论】:

      猜你喜欢
      • 2013-02-19
      • 2017-04-17
      • 1970-01-01
      • 2016-12-22
      • 2021-06-24
      • 1970-01-01
      • 2015-08-12
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多