Concatenation of a variant number of keys of a dictionary Python (recursion?) - python

Hello Stackoverlow members,
I'm trying to concatenate keys (string) on a hand, and values (list) on the other hand, of a dictionnary.
For your better understanding, here is what I have at the beginning:
dict = {'bk1':
{'k11': ['a1', 'b1', 'c1'],
'k12': ['a2', 'b2', 'c2']},
'bk2':
{'k21': ['d1', 'e1'],
'k22': ['d2', 'e2'],
'k23': ['d3', 'e3']},
'bk3':
{'k31': ['f1', 'g1', 'h1'],
'k32': ['f2', 'g2', 'h2']}
}
And here is what I would like at the end:
newdict = {'k11_k21_k31': ['a1', 'b1', 'c1', 'd1', 'e1', 'f1', 'g1', 'h1'],
'k11_k21_k32': ['a1', 'b1', 'c1', 'd1', 'e1', 'f2', 'g2', 'h2'],
'k11_k22_k31': ['a1', 'b1', 'c1', 'd2', 'e2', 'f1', 'g1', 'h1'],
'k11_k22_k32': ['a1', 'b1', 'c1', 'd2', 'e2', 'f2', 'g2', 'h2'],
'k11_k23_k31': ['a1', 'b1', 'c1', 'd3', 'e3', 'f1', 'g1', 'h1'],
'k11_k23_k32': ['a1', 'b1', 'c1', 'd3', 'e3', 'f2', 'g2', 'h2'],
'k12_k21_k31': ['a2', 'b2', 'c2', 'd1', 'e1', 'f1', 'g1', 'h1'],
'k12_k21_k32': ['a2', 'b2', 'c2', 'd1', 'e1', 'f2', 'g2', 'h2'],
'k12_k22_k31': ['a2', 'b2', 'c2', 'd2', 'e2', 'f1', 'g1', 'h1'],
'k12_k22_k32': ['a2', 'b2', 'c2', 'd2', 'e2', 'f2', 'g2', 'h2'],
'k12_k23_k31': ['a2', 'b2', 'c2', 'd3', 'e3', 'f1', 'g1', 'h1'],
'k12_k23_k32': ['a2', 'b2', 'c2', 'd3', 'e3', 'f2', 'g2', 'h2']}
I wish to do that with:
a variant number of "big key" (bki), and for each bki, a variant number of key (kij).
"Full combination" between "big keys". For example, I don't expect results like:
{'k11_k23': ['a1', 'b1', 'c1', 'd3', 'e3']}
where the "bk3" is missed.
I tried with imbricated "for" loops but the number of loops is depending on the number of "big keys"...
Then, I felt that the problem could be solved with recursion (maybe?), but in spite of my research and my will to implement it, I failed.
Any help with "recursive or not" solution would be strongly appreciated.
Thank you,
Mat
Whoaa, what a reactivity!
Thanks a lot for all your quick answers, it works perfect!

As suggested by #jksnw in the comments, you can use itertools.product to do this:
import itertools
dct = {
'bk1': {
'k11': ['a1', 'b1', 'c1'],
'k12': ['a2', 'b2', 'c2']
},
'bk2':{
'k21': ['d1', 'e1'],
'k22': ['d2', 'e2'],
'k23': ['d3', 'e3']
},
'bk3': {
'k31': ['f1', 'g1', 'h1'],
'k32': ['f2', 'g2', 'h2']
}
}
big_keys = dct.keys()
small_keys = (dct[big_key].keys() for big_key in big_keys)
res = {}
for keys_from_each in itertools.product(*small_keys):
key = "_".join(keys_from_each)
value = []
for big_key, small_key in zip(big_keys, keys_from_each):
value.extend(dct[big_key][small_key])
res[key] = value
So that:
>>> res
{'k11_k21_k31': ['a1', 'b1', 'c1', 'd1', 'e1', 'f1', 'g1', 'h1'],
'k11_k21_k32': ['a1', 'b1', 'c1', 'd1', 'e1', 'f2', 'g2', 'h2'],
'k11_k22_k31': ['a1', 'b1', 'c1', 'd2', 'e2', 'f1', 'g1', 'h1'],
'k11_k22_k32': ['a1', 'b1', 'c1', 'd2', 'e2', 'f2', 'g2', 'h2'],
'k11_k23_k31': ['a1', 'b1', 'c1', 'd3', 'e3', 'f1', 'g1', 'h1'],
'k11_k23_k32': ['a1', 'b1', 'c1', 'd3', 'e3', 'f2', 'g2', 'h2'],
'k12_k21_k31': ['a2', 'b2', 'c2', 'd1', 'e1', 'f1', 'g1', 'h1'],
'k12_k21_k32': ['a2', 'b2', 'c2', 'd1', 'e1', 'f2', 'g2', 'h2'],
'k12_k22_k31': ['a2', 'b2', 'c2', 'd2', 'e2', 'f1', 'g1', 'h1'],
'k12_k22_k32': ['a2', 'b2', 'c2', 'd2', 'e2', 'f2', 'g2', 'h2'],
'k12_k23_k31': ['a2', 'b2', 'c2', 'd3', 'e3', 'f1', 'g1', 'h1'],
'k12_k23_k32': ['a2', 'b2', 'c2', 'd3', 'e3', 'f2', 'g2', 'h2']}
Here, itertools.product is used to get a list of the "small keys" that we take from each block:
>>> big_keys = dct.keys()
>>> small_keys = (dct[big_key].keys() for big_key in big_keys)
>>> list(itertools.product(*small_keys))
[('k12', 'k22', 'k31'),
('k12', 'k22', 'k32'),
('k12', 'k23', 'k31'),
('k12', 'k23', 'k32'),
('k12', 'k21', 'k31'),
('k12', 'k21', 'k32'),
('k11', 'k22', 'k31'),
('k11', 'k22', 'k32'),
('k11', 'k23', 'k31'),
('k11', 'k23', 'k32'),
('k11', 'k21', 'k31'),
('k11', 'k21', 'k32')]

You can use itertools.product, and reduce(lambda x,y:x+y,i) to flatten your nested lists , also do not use dict or other python built-in types name or keywords as your variables name (i used d) :
>>> from itertools import product
>>> v=[i.values() for i in d.values()]
>>> v=[reduce(lambda x,y:x+y,i) for i in product(*v)]
>>> k=[i.keys() for i in d.values()]
>>> k=['_'.join(i) for i in product(*k)]
>>> {k:v for k,v in zip(k,v)}
{'k31_k12_k22': ['f1', 'g1', 'h1', 'a2', 'b2', 'c2', 'd2', 'e2'],
'k32_k12_k21': ['f2', 'g2', 'h2', 'a2', 'b2', 'c2', 'd1', 'e1'],
'k31_k11_k22': ['f1', 'g1', 'h1', 'a1', 'b1', 'c1', 'd2', 'e2'],
'k31_k12_k23': ['f1', 'g1', 'h1', 'a2', 'b2', 'c2', 'd3', 'e3'],
'k32_k12_k22': ['f2', 'g2', 'h2', 'a2', 'b2', 'c2', 'd2', 'e2'],
'k31_k12_k21': ['f1', 'g1', 'h1', 'a2', 'b2', 'c2', 'd1', 'e1'],
'k32_k11_k23': ['f2', 'g2', 'h2', 'a1', 'b1', 'c1', 'd3', 'e3'],
'k32_k12_k23': ['f2', 'g2', 'h2', 'a2', 'b2', 'c2', 'd3', 'e3'],
'k31_k11_k21': ['f1', 'g1', 'h1', 'a1', 'b1', 'c1', 'd1', 'e1'],
'k31_k11_k23': ['f1', 'g1', 'h1', 'a1', 'b1', 'c1', 'd3', 'e3'],
'k32_k11_k21': ['f2', 'g2', 'h2', 'a1', 'b1', 'c1', 'd1', 'e1'],
'k32_k11_k22': ['f2', 'g2', 'h2', 'a1', 'b1', 'c1', 'd2', 'e2']}

Related

Split data in list based on condition

I have following list :
data = ['A1', 'C3', 'B2', 'A2', 'D3', 'C2', 'A3', 'D2', 'C1', 'B1', 'D1', 'B3']
I want to split the list such that
split1 = ['A1', 'C3', 'B2', 'A2', 'C2', 'A3', 'C1', 'B1', 'B3']
split2 = ['D3', 'D2', 'D1']
Constraint is that no item with same prefix(A, B, etc.) can wind up in separate list. The data can be split in any ratio like 50-50, 80-20.
Here you go:
import numpy as np
data = np.array(['A1', 'C3', 'B2', 'A2', 'D3', 'C2', 'A3', 'D2', 'C1', 'B1', 'D1', 'B3'])
# define some condition
condition = ['B', 'D']
boolean_selection = [np.any([ c in d for c in condition]) for d in data]
split1 = data[boolean_selection]
split2 = data[np.logical_not(boolean_selection)]

Python saving results to variables

I am trying to loop through an array and I am checking where I have connection. (from an other function comes back a 0 or 1)
The bold arrays should be my results. I want to save them to a global variable, myResults, but if I print it at the end, then I will get back a much longer array...
I think the global variable is overwritten, why does it happen?
Thank you :)
[[['A2', 'A1', 'B1', 'B2', 'B3'], 'A3'], 26]
[[['A2', 'A1', 'B1', 'B2', 'B3', 'B4', 'A4'], 'A3'], 32]
[[[['A2', 'A1', 'B1', 'B2', 'B3', 'B4', 'A4', 'B4', 'C4', 'C3', 'C2', 'C1', 'D1', 'D2', 'D3', 'D4', 'D3', 'D4', 'D3', 'D4', 'D3', 'D4', 'D3', 'D4', 'D3', 'D4', 'D3', 'D4', 'C4', 'D4', 'C4', 'D4', 'C4', 'D4', 'C4', 'D4'], 'A3'], 26], [[['A2', 'A1', 'B1', 'B2', 'B3', 'B4', 'A4', 'B4', 'C4', 'C3', 'C2', 'C1', 'D1', 'D2', 'D3', 'D4', 'D3', 'D4', 'D3', 'D4', 'D3', 'D4', 'D3', 'D4', 'D3', 'D4', 'D3', 'D4', 'C4', 'D4', 'C4', 'D4', 'C4', 'D4', 'C4', 'D4'], 'A3'], 32]]
def callbackFunction(start, end, time):
myResult = []
def logToVariable(path, goal, timeFor):
finalPath = path
finalPath.append(goal)
print(finalPath)
add_result = [finalPath, timeFor]
print(add_result)
myResult.append(add_result)
def innerLoop(start, end, time):
correctList = [item for item in myList if item not in start]
for i in correctList:
first = start[-1]
time_diff = directPoints(first, i, time)
if time_diff[1] == 1:
if i==end:
#new_result = []
new_result = [[start, i], time_diff[0]]
#logToVariable(start, i, time_diff[0])
# print(start, i)
myResult.append(new_result)
print(new_result)
#break
#return result
else:
start.append(i)
innerLoop(start, end, time_diff[0])
else:
continue
innerLoop(start, end, time)
print(myResult)
return myResult

haw can I find the smallest list among some lists generated by my program?

I wrote a program that generates some lists, something like
['a0', 'a1', 'a2', 'a3', 'a3', 'a4', 'C', 'b4', 'b3', 'b2', 'b2', 'b3', 'b4', 'b5', 'b5', 'b4', 'D', 'c4']
['a0', 'a1', 'a2', 'a3', 'a3', 'a4', 'C', 'b4', 'b3', 'b2', 'b2', 'b3', 'b4', 'D', 'c4', 'c4', 'D', 'b4', 'b5']
['a0', 'a1', 'a2', 'a3', 'a3', 'a4', 'C', 'b4', 'b5', 'b5', 'b4', 'b3', 'b2', 'b2', 'b3', 'b4', 'D', 'c4']
['a0', 'a1', 'a2', 'a3', 'a3', 'a4', 'C', 'b4', 'b5', 'b5', 'b4', 'D', 'c4', 'c4', 'D', 'b4', 'b3', 'b2']
['a0', 'a1', 'a2', 'a3', 'a3', 'a4', 'C', 'b4', 'D', 'c4', 'c4', 'D', 'b4', 'b3', 'b2', 'b2', 'b3', 'b4', 'b5']
['a0', 'a1', 'a2', 'a3', 'a3', 'a4', 'C', 'b4', 'D', 'c4', 'c4', 'D', 'b4', 'b5', 'b5', 'b4', 'b3', 'b2']
and I want to find the shortest list, the list that has the minimum number of elements
thanks,
You can use the min function:
min(data, key = len)
If you want to handle cases where there are multiple elements having the shortest length, you can sort the list in ascending order by length:
sorted(data, key = len)
You can sort it by list length then get the first element but this won't take into account lists that all have the same length.
smallest_list = sorted(list_of_list, key=len)[0]
Another would be get the length of the smallest list then use that as a filter
len_smallest_list = min(len(x) for x in list_of_list)
smallest_list = [list for list in list_of_list if len(list) == len_smallest_list]

How to find different combinations between two list?

There are two lists.
list_1=[a1,b1,c1,d1]
list_2=[a2,b2,c2,d2]
Conditions are (i) there must be four elements in each of the combinations and (ii) combinations should contain one element of a (i.e. either a1 or a2),one element of b (i.e. either b1 or b2),one element of c (i.e. either c1 or c2) and one element of d (i.e. either d1 or d2).
Please help me to find out different combinations by using python 3x.
You can use itertools.product:
from itertools import product
list_1 = ['a1','b1','c1','d1']
list_2 = ['a2','b2','c2','d2']
result = list(product(*zip(list_1, list_2)))
print(result)
[('a1', 'b1', 'c1', 'd1'), ('a1', 'b1', 'c1', 'd2'), ('a1', 'b1', 'c2', 'd1'), ('a1', 'b1', 'c2', 'd2'), ('a1', 'b2', 'c1', 'd1'), ('a1', 'b2', 'c1', 'd2'), ('a1', 'b2', 'c2', 'd1'), ('a1', 'b2', 'c2', 'd2'), ('a2', 'b1', 'c1', 'd1'), ('a2', 'b1', 'c1', 'd2'), ('a2', 'b1', 'c2', 'd1'), ('a2', 'b1', 'c2', 'd2'), ('a2', 'b2', 'c1', 'd1'), ('a2', 'b2', 'c1', 'd2'), ('a2', 'b2', 'c2', 'd1'), ('a2', 'b2', 'c2', 'd2')]

List of Lists to List of Dictionaries

How can I convert a list of lists into a list of dictionaries?
More specifiicaly: How do I go from this:
[['a1', 'b1', 'c1', 'd1', 'e1', 'f1', 'g1', 'h1', 'i1'], ['a2', 'b2', 'c2', 'd2', 'e2', 'f2', 'g2', 'h2', 'i2'], ['a3', 'b3', 'c3', 'd3', 'e3', 'f3', 'g3', 'h3', 'i3'], ['a4', 'b4', 'c4', 'd4', 'e4', 'f4', 'g4', 'h4', 'i4'], ['a5', 'b5', 'c5', 'd5', 'e5', 'f5', 'g5', 'h5', 'i5'], ['a6', 'b6', 'c6', 'd6', 'e6', 'f6', 'g6', 'h6', 'i6'], ['a7', 'b7', 'c7', 'd7', 'e7', 'f7', 'g7', 'h7', 'i7'], ['a8', 'b8', 'c8', 'd8', 'e8', 'f8', 'g8', 'h8', 'i8'], ['a9', 'b9', 'c9', 'd9', 'e9', 'f9', 'g9', 'h9', 'i9']]
to this:
[{'a1': None, 'b1': None, 'c1': None, 'd1': None, 'e1': None, 'f1': None, 'g1': None, 'h1': None, 'i1': None}, #etc
In [20]: l = [['a1', 'b1', 'c1', 'd1', 'e1', 'f1', 'g1', 'h1', 'i1'], ['a2', 'b2', 'c2', 'd2', 'e2', 'f2', 'g2', 'h2', 'i2'], ['a3', 'b3', 'c3', 'd3', 'e3', 'f3', 'g3', 'h3', 'i3'], ['a4', 'b4', 'c4', 'd4', 'e4', 'f4', 'g4', 'h4', 'i4'], ['a5', 'b5', 'c5', 'd5', 'e5', 'f5', 'g5', 'h5', 'i5'], ['a6', 'b6', 'c6', 'd6', 'e6', 'f6', 'g6', 'h6', 'i6'], ['a7', 'b7', 'c7', 'd7', 'e7', 'f7', 'g7', 'h7', 'i7'], ['a8', 'b8', 'c8', 'd8', 'e8', 'f8', 'g8', 'h8', 'i8'], ['a9', 'b9', 'c9', 'd9', 'e9', 'f9', 'g9', 'h9', 'i9']]
In [21]: map(dict.fromkeys, l)
Out[21]:
[{'a1': None,
'b1': None,
'c1': None,
'd1': None,
'e1': None,
'f1': None,
'g1': None,
'h1': None,
'i1': None},
{'a2': None,
'b2': None,
'c2': None,
'd2': None,
...
This will work with any iterable of iterables, not just a list of lists (provided, of course, that the second-level elements are hashable).
In Python 2, the above code returns a list.
In Python 3, it returns an iterable. If you require a list, you could use list(map(dict.fromkeys, l)).
Try this:
l = [['a1', 'b1', 'c1', 'd1', 'e1', 'f1', 'g1', 'h1', 'i1'], ['a2', 'b2', 'c2', 'd2', 'e2', 'f2', 'g2', 'h2', 'i2'], ['a3', 'b3', 'c3', 'd3', 'e3', 'f3', 'g3', 'h3', 'i3'], ['a4', 'b4', 'c4', 'd4', 'e4', 'f4', 'g4', 'h4', 'i4'], ['a5', 'b5', 'c5', 'd5', 'e5', 'f5', 'g5', 'h5', 'i5'], ['a6', 'b6', 'c6', 'd6', 'e6', 'f6', 'g6', 'h6', 'i6'], ['a7', 'b7', 'c7', 'd7', 'e7', 'f7', 'g7', 'h7', 'i7'], ['a8', 'b8', 'c8', 'd8', 'e8', 'f8', 'g8', 'h8', 'i8'], ['a9', 'b9', 'c9', 'd9', 'e9', 'f9', 'g9', 'h9', 'i9']]
res = []
for line in l:
res.append(dict((k, None) for k in line))
OR:
res = [dict((k, None) for k in line) for line in l]

Categories

Resources