簡體   English   中英

從列表字典創建n個嵌套循環

[英]creating n nested loops from a dictionary of lists

我有一本有n個鍵的字典,每個鍵都包含n個字符串的列表。

我想遍歷字符串的每個組合,產生鍵和與其關聯的字符串。

這是一個具有3個鍵的字典的示例,但我想歸納為具有n個鍵的字典。

dict = {'key1':['str0','str1','str2','strn'],'key2':['apples','bananas','mangos'],'key3':['spam','eggs','more spam']}

for str1 in dict['key1']:
    for str2 in dict['key2']:
        for str3 in dict['key3']:
            print 'key1'+"."+str1,'key2'+"."+str2,'key3'+"."+str3

請回答問題時,您能否描述答案的工作方式,因為我是python的新手,還不知道所有可用的工具!

預期產量:

key1.str0 key2.apples key3.spam
key1.str0 key2.apples key3.eggs
key1.str0 key2.apples key3.more spam
key1.str0 key2.bananas key3.spam
key1.str0 key2.bananas key3.eggs
...

n維迭代器的預期輸出:

key1.str0 key2.apples key3.spam ... keyn.string0
key1.str0 key2.apples key3.spam ... keyn.string1
key1.str0 key2.apples key3.spam ... keyn.string2
...
key1.str0 key2.apples key3.spam ... keyn.stringn
...

您應該使用itertools.product ,它執行笛卡爾乘積 ,這是您要嘗試執行的操作的名稱。

from itertools import product

# don't shadow the built-in name `dict`
d = {'key1': ['str0','str1','str2','strn'], 'key2': ['apples','bananas','mangos'], 'key3': ['spam','eggs','more spam']}

# dicts aren't sorted, but you seem to want key1 -> key2 -> key3 order, so 
# let's get a sorted copy of the keys
keys = sorted(d.keys())
# and then get the values in the same order
values = [d[key] for key in keys]

# perform the Cartesian product
# product(*values) means product(values[0], values[1], values[2], ...)
results = product(*values)

# each `result` is something like ('str0', 'apples', 'spam')
for result in results:
    # pair up each entry in `result` with its corresponding key
    # So, zip(('key1', 'key2', 'key3'), ('str0', 'apples', 'spam'))
    # yields (('key1', 'str0'), ('key2', 'apples'), ('key3', 'spam'))
    # schematically speaking, anyway
    for key, thing in zip(keys, result):
        print key + '.' + thing, 
    print

請注意,我們在哪里都沒有對字典中的鍵數進行硬編碼。 如果使用collections.OrderedDict而不是dict則可以避免排序。


如果要將鍵附加到它們的值,這是另一個選擇:

from itertools import product

d = {'key1': ['str0','str1','str2','strn'], 'key2': ['apples','bananas','mangos'], 'key3': ['spam','eggs','more spam']}

foo = [[(key, value) for value in d[key]] for key in sorted(d.keys())]

results = product(*foo)
for result in results:
    for key, value in result:
        print key + '.' + value,
    print

在這里,我們構造(鍵,值)元組的列表列表,然后將笛卡爾乘積應用於列表。 這樣,鍵和值之間的關系完全包含在results 想一想,這可能比我發布的第一種方法更好。

您可以使用遞歸函數:

# make a list of all the keys
keys = list(dict.keys())

def f(keys, dict, depth=0, to_print=[]):
    if depth < len(keys):
        for item in dict[keys[depth]]:
            to_print.append(keys[depth] + '.' + item + ' ')
            f(keys, dict, depth + 1, to_print)
            del to_print[-1]
    else:
        # you can format the output as you wish; here i'm just printing the list
        print to_print


# call the function
f(keys, dict)

我本來想要一種更實用的樣式,它基本上與@Senshin的答案相同:

import itertools
from pprint import pprint
def foo(d):
    def g(item):
        """create and return key.value1, key.value2, ..., key.valueN iterator

        item is a (key, value) dictionary item, assumes value is a sequence/iterator
        """
        # associate the key with each value - (key, value0) ... (key, valueN)
        kay_vees = itertools.izip(itertools.repeat(item[0]), item[1])
        return itertools.imap('.'.join, kay_vees)

    # generator that produces n data sets from the dict
    a = itertools.imap(g, d.iteritems())

    # cartesian product of the datasets
    return itertools.product(*a)

用法:

c = list(foo(d))
pprint(c)

for thing in foo(d):
    print thing

一旦消耗完,迭代器就需要重新定義 foo將為每個調用返回一個新的迭代器。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM