列表字典的笛卡尔积

发布于 2024-10-20 22:06:44 字数 552 浏览 5 评论 0原文

我正在尝试编写一些代码来测试一堆输入参数的笛卡尔积。

我查看了 itertools,但它的 product 功能并不完全是我想要的。是否有一种简单明显的方法来获取具有任意数量的键每个值中任意数量的元素的字典,然后生成具有下一个排列的字典?

输入:

options = {"number": [1,2,3], "color": ["orange","blue"] }
print list( my_product(options) )

示例输出:

[ {"number": 1, "color": "orange"},
  {"number": 1, "color": "blue"},
  {"number": 2, "color": "orange"},
  {"number": 2, "color": "blue"},
  {"number": 3, "color": "orange"},
  {"number": 3, "color": "blue"}
]

I'm trying to write some code to test out the Cartesian product of a bunch of input parameters.

I've looked at itertools, but its product function is not exactly what I want. Is there a simple obvious way to take a dictionary with an arbitrary number of keys and an arbitrary number of elements in each value, and then yield a dictionary with the next permutation?

Input:

options = {"number": [1,2,3], "color": ["orange","blue"] }
print list( my_product(options) )

Example output:

[ {"number": 1, "color": "orange"},
  {"number": 1, "color": "blue"},
  {"number": 2, "color": "orange"},
  {"number": 2, "color": "blue"},
  {"number": 3, "color": "orange"},
  {"number": 3, "color": "blue"}
]

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

伤痕我心 2024-10-27 22:06:44

好的,谢谢@dfan 告诉我我找错地方了。我现在明白了:

from itertools import product
def my_product(inp):
    return (dict(zip(inp.keys(), values)) for values in product(*inp.values())

编辑:经过多年的Python经验,我认为更好的解决方案是接受kwargs而不是输入字典;调用风格更类似于原始的itertools.product。另外,我认为编写生成器函数,而不是返回生成器表达式的函数,可以使代码更清晰。所以:

import itertools
def product_dict(**kwargs):
    keys = kwargs.keys()
    for instance in itertools.product(*kwargs.values()):
        yield dict(zip(keys, instance))

如果你需要传入一个字典,list(product_dict(**mydict))。使用 kwargs 而不是任意输入类的一个显着变化是它会阻止键/值排序,至少在 Python 3.6 之前是这样。

Ok, thanks @dfan for telling me I was looking in the wrong place. I've got it now:

from itertools import product
def my_product(inp):
    return (dict(zip(inp.keys(), values)) for values in product(*inp.values())

EDIT: after years more Python experience, I think a better solution is to accept kwargs rather than a dictionary of inputs; the call style is more analogous to that of the original itertools.product. Also I think writing a generator function, rather than a function that returns a generator expression, makes the code clearer. So:

import itertools
def product_dict(**kwargs):
    keys = kwargs.keys()
    for instance in itertools.product(*kwargs.values()):
        yield dict(zip(keys, instance))

and if you need to pass in a dict, list(product_dict(**mydict)). The one notable change using kwargs rather than an arbitrary input class is that it prevents the keys/values from being ordered, at least until Python 3.6.

风筝有风,海豚有海 2024-10-27 22:06:44

Seth 的答案的 Python 3 版本。

import itertools

def dict_product(options):
    """
    >>> list(dict_product({'number': [1, 2], 'character': 'ab'}))
    [{'character': 'a', 'number': 1},
     {'character': 'a', 'number': 2},
     {'character': 'b', 'number': 1},
     {'character': 'b', 'number': 2}]
    """
    return (dict(zip(options.keys(), x)) for x in itertools.product(*options.values()))

Python 3 version of Seth's answer.

import itertools

def dict_product(options):
    """
    >>> list(dict_product({'number': [1, 2], 'character': 'ab'}))
    [{'character': 'a', 'number': 1},
     {'character': 'a', 'number': 2},
     {'character': 'b', 'number': 1},
     {'character': 'b', 'number': 2}]
    """
    return (dict(zip(options.keys(), x)) for x in itertools.product(*options.values()))
差↓一点笑了 2024-10-27 22:06:44

顺便说一句,这不是排列。排列是列表的重新排列。这是列表中可能的选择的枚举。

编辑:在记住它被称为笛卡尔积之后,我想出了这个:

import itertools
options = {"number": [1,2,3], "color": ["orange","blue"] }
product = [x for x in apply(itertools.product, options.values())]
print([dict(zip(options.keys(), p)) for p in product])

By the way, this is not a permutation. A permutation is a rearrangement of a list. This is an enumeration of possible selections from lists.

Edit: after remembering that it was called a Cartesian product, I came up with this:

import itertools
options = {"number": [1,2,3], "color": ["orange","blue"] }
product = [x for x in apply(itertools.product, options.values())]
print([dict(zip(options.keys(), p)) for p in product])
我也只是我 2024-10-27 22:06:44
# I would like to do
keys,values = options.keys(), options.values()
# but I am not sure that the keys and values would always
# be returned in the same relative order. Comments?
keys = []
values = []
for k,v in options.iteritems():
    keys.append(k)
    values.append(v)

import itertools
opts = [dict(zip(keys,items)) for items in itertools.product(*values)]

结果

opts = [
    {'color': 'orange', 'number': 1},
    {'color': 'orange', 'number': 2},
    {'color': 'orange', 'number': 3},
    {'color': 'blue', 'number': 1},
    {'color': 'blue', 'number': 2},
    {'color': 'blue', 'number': 3}
]
# I would like to do
keys,values = options.keys(), options.values()
# but I am not sure that the keys and values would always
# be returned in the same relative order. Comments?
keys = []
values = []
for k,v in options.iteritems():
    keys.append(k)
    values.append(v)

import itertools
opts = [dict(zip(keys,items)) for items in itertools.product(*values)]

results in

opts = [
    {'color': 'orange', 'number': 1},
    {'color': 'orange', 'number': 2},
    {'color': 'orange', 'number': 3},
    {'color': 'blue', 'number': 1},
    {'color': 'blue', 'number': 2},
    {'color': 'blue', 'number': 3}
]
分分钟 2024-10-27 22:06:44

这就是我想到的:

from itertools import product

def dctproduct(dct):
    """
    >>> list(dctproduct({'number': [1, 2], 'character': 'ab'}))
    [{'number': 1, 'character': 'a'}, {'number': 1, 'character': 'b'}, {'number': 2, 'character': 'a'}, {'number': 2, 'character': 'b'}]
    """        
    keys = dct.keys()
    for vals in product(*dct.values()):
        yield dict(zip(keys, vals))

这也可以用于有效地调用具有关键字参数的所有组合的函数:

def kwproduct(**kwargs):
    """
    >>> for kwargs in kwproduct(number=[1, 2], character='ab'):
    >>>     print(kwargs)
    {'number': 1, 'character': 'a'}
    {'number': 1, 'character': 'b'}
    {'number': 2, 'character': 'a'}
    {'number': 2, 'character': 'b'}        
    """
    return dctproduct(kwargs)

kwproduct 相对于 dictproduct 的好处是你不需要不需要创建一个 dict 但它显然限制您使用有效的参数名称作为键。

This is what I have come up with:

from itertools import product

def dctproduct(dct):
    """
    >>> list(dctproduct({'number': [1, 2], 'character': 'ab'}))
    [{'number': 1, 'character': 'a'}, {'number': 1, 'character': 'b'}, {'number': 2, 'character': 'a'}, {'number': 2, 'character': 'b'}]
    """        
    keys = dct.keys()
    for vals in product(*dct.values()):
        yield dict(zip(keys, vals))

This can also be used to efficiently call a function with all combinations of keyword arguments:

def kwproduct(**kwargs):
    """
    >>> for kwargs in kwproduct(number=[1, 2], character='ab'):
    >>>     print(kwargs)
    {'number': 1, 'character': 'a'}
    {'number': 1, 'character': 'b'}
    {'number': 2, 'character': 'a'}
    {'number': 2, 'character': 'b'}        
    """
    return dctproduct(kwargs)

The benefit of kwproduct over dictproduct is that you don't need to create a dict but it obviously limits you to use valid argument names as keys.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文