Home > Back-end >  Why itertools.product dosen't return key and value from a dictionary in sequence? Help pls
Why itertools.product dosen't return key and value from a dictionary in sequence? Help pls

Time:02-18

I have a situation that is as follows. A nested loop like this:

d = [{'val1': 1, 'val2':2}, {'val3': 3, 'val4':4}, {'val5': 5, 'val6':6}, {'val7': 7, 'val8':8}, {'val9': 9, 'val10':10}]

num = list(range(len(d))
new_list = []
for i in num:
  for k, v in d[i].items():
    new_list.append([k ,v])

The result will be this:

[['val1', 1],
 ['val2', 2],
 ['val3', 3],
 ['val4', 4],
 ['val5', 5],
 ['val6', 6],
 ['val7', 7],
 ['val8', 8],
 ['val9', 9],
 ['val10', 10]]

Bu need to find a way to summarize these loops, either using functions like Map and Filter, or with the Itertools.product I read that turns nested loops into a loop only. So I made this code:

new_list = []
for i, (k,v) in itertools.product(num, d[i].items()):
    new_list.append([k ,v])

And the result is this:

    [['val9', 9],
 ['val10', 10],
 ['val9', 9],
 ['val10', 10],
 ['val9', 9],
 ['val10', 10],
 ['val9', 9],
 ['val10', 10],
 ['val9', 9],
 ['val10', 10]]

So I wanted to know if there is any way for itertools.product to produce the same result as the code with nested loops, that is, the outputs are in sequence and not just repeating the last two values. If there is a solution with map or filter, it is also welcome.

Update

@BrokenBenchmark My problem is a little more complex, so can you helpe me? The problem is this:

d = [{'val1': 1, 'val2':2}, {'val3': 3, 'val4':4}, {'val5': 5, 'val6':6}, {'val7': 7, 'val8':8}, {'val9': 9, 'val10':10}]  
d2 = [{'val1': 1, 'val2':2}, {'val3': 3, 'val4':4}, {'val5': 5, 'val6':6}, {'val7': 7, 'val8':8}, {'val9': 9, 'val10':10}]  
num = list(range(len(d))
new_list = []  
for i in num:      
    for k_i, v_i in d[i].items():
          for j in num:              
              for k_j, v_j in d2[j].items():                  
                  new_list.append([k_i, k_j])

Do you have a solution for that? That can replace this nested loop for something that speed up the code.

The output that I need is lists with key from dict 1 along with all keys from dict 2 (I need to compare each key from dict 1 with each key from dict 2). The output should be this:

[['Key1_dict1', 'Key1_dict2'],
['Key1_dict1', 'Key2_dict2'],
['Key1_dict1', 'Key3_dict2'],
['Key1_dict1', 'Key4_dict2'],
['Key1_dict1', 'Key5_dict2'],
['Key1_dict1', 'Key6_dict2'],
['Key1_dict1', 'Key7_dict2'],
['Key1_dict1', 'Key8_dict2'],
['Key1_dict1', 'Key9_dict2'],
['Key1_dict1', 'Key10_dict2'],
['Key2_dict1', 'Key1_dict2'],
['Key2_dict1', 'Key2_dict2'],
['Key2_dict1', 'Key3_dict2'],
['Key2_dict1', 'Key4_dict2'],
['Key2_dict1', 'Key5_dict2'],
['Key2_dict1', 'Key6_dict2'],
['Key2_dict1', 'Key7_dict2'],
['Key2_dict1', 'Key8_dict2'],
['Key2_dict1', 'Key9_dict2'],
['Key2_dict1', 'Key10_dict2']]

And so on.

CodePudding user response:

Solution #1:

        d = [{'val1': 1, 'val2':2}, {'val3': 3, 'val4':4}, {'val5': 5, 'val6':6}, {'val7': 7, 'val8':8}, {'val9': 9, 'val10':10}]  
        d2 = [{'val1': 1, 'val2':2}, {'val3': 3, 'val4':4}, {'val5': 5, 'val6':6}, {'val7': 7, 'val8':8}, {'val9': 9, 'val10':10}]

        new_list = [[k_i, k_j] for i in range(len(d)) for k_i, v_i in d[i].items() for j in range(len(d2)) for k_j, v_j in d2[j].items()]

Output:

[['val1', 'val1'], ['val1', 'val2'], ['val1', 'val3'], ['val1', 'val4'], ['val1', 'val5'], ['val1', 'val6'], ['val1', 'val7'], ['val1', 'val8'], ['val1', 'val9'], ['val1', 'val10'], ['val2', 'val1'], ['val2', 'val2'], ['val2', 'val3'], ['val2', 'val4'], ['val2', 'val5'], ['val2', 'val6'], ['val2', 'val7'], ['val2', 'val8'], ['val2', 'val9'], ['val2', 'val10'], ['val3', 'val1'], ['val3', 'val2'], ['val3', 'val3'], ['val3', 'val4'], ['val3', 'val5'], ['val3', 'val6'], ['val3', 'val7'], ['val3', 'val8'], ['val3', 'val9'], ['val3', 'val10'], ['val4', 'val1'], ['val4', 'val2'], ['val4', 'val3'], ['val4', 'val4'], ['val4', 'val5'], ['val4', 'val6'], ['val4', 'val7'], ['val4', 'val8'], ['val4', 'val9'], ['val4', 'val10'], ['val5', 'val1'], ['val5', 'val2'], ['val5', 'val3'], ['val5', 'val4'], ['val5', 'val5'], ['val5', 'val6'], ['val5', 'val7'], ['val5', 'val8'], ['val5', 'val9'], ['val5', 'val10'], ['val6', 'val1'], ['val6', 'val2'], ['val6', 'val3'], ['val6', 'val4'], ['val6', 'val5'], ['va...

Solution # 2:

        k, k2 = chain(*[m.keys() for m in d]), chain(*[m.keys() for m in d2])
        new_list_of_tuples = list(product(k, k2)) # if tuples are OK as key pairs
        new_list = [[*x] for x in product(k, k2)] # if you need lists as key pairs

CodePudding user response:

If you don't want to use a nested for loop, you can use .extend() to append the key-value pairs of a dictionary to a list, and use map() to transform each element in .items() to a list.

itertools.product() can reduce nesting in for loops, when, for example, you need to loop over each pair of elements in two lists. It is not a silver bullet for removing all nested for loops.

data = [{'val1': 1, 'val2':2}, {'val3': 3, 'val4':4}, {'val5': 5, 'val6':6}, {'val7': 7, 'val8':8}, {'val9': 9, 'val10':10}]

result = []
for dictionary in data:
    result.extend(map(list, dictionary.items()))    

print(result)
  • Related