Nested lists to nested dicts - python

I've a list with master keys and a list of list of lists, where the first value of each enclosed list (like 'key_01') shall be a sub key for the corresponding values (like 'val_01', 'val_02'). The data is shown here:
master_keys = ["Master_01", "Master_02", "Master_03"]
data_long = [[['key_01','val_01','val_02'],['key_02','val_03','val_04'], ['key_03','val_05','val_06']],
[['key_04','val_07','val_08'], ['key_05','val_09','val_10'], ['key_06','val_11','val_12']],
[['key_07','val_13','val_14'], ['key_08','val_15','val_16'], ['key_09','val_17','val_18']]]
I would like these lists to be combined into a dictionary of dictionaries, like this:
master_dic = {
"Master_01": {'key_01':['val_01','val_02'],'key_02': ['val_03','val_04'], 'key_03': ['val_05','val_06']},
"Master_02": {'key_04': ['val_07','val_08'], 'key_05': ['val_09','val_10'], 'key_06': ['val_11','val_12']},
"Master_03": {'key_07': ['val_13','val_14'], ['key_08': ['val_15','val_16'], 'key_09': ['val_17','val_18']}
}
What I've got so far is the sub dict:
import itertools
master_dic = {}
servant_dic = {}
keys = []
values = []
for line in data_long:
for item in line:
keys.extend(item[:1])
values.append(item[1:])
servant_dic = dict(itertools.izip(keys, values))
Which puts out a dictionary, as expected.
servant_dic = {
'key_06': ['val_11','val_12'], 'key_04': ['val_08','val_07'], 'key_05': ['val_09','val_10'],
'key_02': ['val_03','val_04'], 'key_03': ['val_05','val_06'], 'key_01': ['val_01','val_02']
}
The problem is, that if I want to add the master_keys to this dictionary, so I get the wanted result, I'd have to do this in a certain order, which would be possible, if each line had a counter like this:
enumerated_dic =
{
0: {'key_01':['val_01','val_02'],'key_02': ['val_03','val_04'], 'key_03': ['val_05','val_06']},
1: {'key_04': ['val_07','val_08'], 'key_05': ['val_09','val_10'], 'key_06': ['val_11','val_12']},
2: {'key_07': ['val_13','val_14'], ['key_08': ['val_15','val_16'], 'key_09': ['val_17','val_18']}
}
I'd love to do this with enumerate(), while each line of the servant_dic is build, but can't figure out how. Since afterwards, i could simply replace the counters 0, 1, 2 etc. with the master_keys.
Thanks for your help.

master_keys = ["Master_01", "Master_02", "Master_03"]
data_long = [[['key_01','val_01','val_02'],['key_02','val_03','val_04'], ['key_03','val_05','val_06']],
[['key_04','val_07','val_08'], ['key_05','val_09','val_10'], ['key_06','val_11','val_12']],
[['key_07','val_13','val_14'], ['key_08','val_15','val_16'], ['key_09','val_17','val_18']]]
_dict = {}
for master_key, item in zip(master_keys, data_long):
_dict[master_key] = {x[0]: x[1:] for x in item}
print _dict

Hope this will help:
{master_key: {i[0]: i[1:] for i in subkeys} for master_key, subkeys in zip(master_keys, data_long)}

My functional approach:
master_dic = dict(zip(master_keys, [{k[0]: k[1::] for k in emb_list} for emb_list in data_long]))
print(master_dic)

You can also use pop and a dict comprehension:
for key, elements in zip(master_keys, data_long):
print {key: {el.pop(0): el for el in elements}}
...:
{'Master_01': {'key_02': ['val_03', 'val_04'], 'key_03': ['val_05', 'val_06']}}
{'Master_02': {'key_06': ['val_11', 'val_12'], 'key_04': ['val_07', 'val_08'], 'key_05': ['val_09', 'val_10']}}
{'Master_03': {'key_07': ['val_13', 'val_14'], 'key_08': ['val_15', 'val_16'], 'key_09': ['val_17', 'val_18']}}

Related

Get keys from a dictionary that contains duplicate list values, then store their corresponding keys in a nested list

I've tried to word this the best way that I possibly can, but it will probably be more clear if I provide an example of what I am trying to acheive:
Input:
source_dictionary = {"person1": ["x1","x2","x3","x4"],
"person2": ["x1","x2","x3","x4"],
"person3": ["x1","x2"],
"person4": ["x1","x2"],
"person5": ["x1","x2"]
}
Intended output:
[["person1","person2"],["person3","person4","person5"]]
Handling the lists in the dictionary is proving to be quite a challenge.
Appologies, I forgot to include what I have tried so far. As mentioned above - I am having issues with the lists:
rev_dict = {}
for key, value in source_dictionary.items():
rev_dict.setdefault(value, set()).add(key)
result = [key for key, values in rev_dict.items()
if len(values) > 1]
Assuming you want to join the keys by identical value, use a defaultdict:
source_dictionary = {"person1": ["x1","x2","x3","x4"],
"person2": ["x1","x2","x3","x4"],
"person3": ["x1","x2"],
"person4": ["x1","x2"],
"person5": ["x1","x2"]
}
from collections import defaultdict
d = defaultdict(list)
for key, value in source_dictionary.items():
d[tuple(value)].append(key)
out = list(d.values())
Alternative with setdefault:
d = {}
for key, value in source_dictionary.items():
d.setdefault(tuple(value), []).append(key)
out = list(d.values())
output:
[['person1', 'person2'], ['person3', 'person4', 'person5']]
source_dictionary = {"person1": ["x1","x2","x3","x4"],
"person2": ["x1","x2","x3","x4"],
"person3": ["x1","x2"],
"person4": ["x1","x2"],
"person5": ["x1","x2"]
}
L = []
for i in source_dictionary.values():
K = []
for j in source_dictionary.keys():
if source_dictionary[j] == i :
K.append(j)
if K not in L:
L.append(K)
print(L)

How could I create a dictionary taking specific strings of elements of a list?

I have a list with elements that contain values separated by "_" and I need to take the 4th as the values and the 5 and 6th as keys of a dictionary
My list:
['MLID_D_08_NGS_34_H08.fsa',
'MLID_D_17_W2205770_Michael_Jordan_A10.fsa',
'MLID_D_18_W2205770_Michael_Jordan_B10.fsa',
'MLID_D_19_W2205768_Maradona_Guti_C10.fsa',
'MLID_D_20_W2205768_Maradona_Guti_D10.fsa',
'MLID_D_38_No_DNA_F12.fsa']
I am trying to get a dictionary like this
thisdict = {
"34_H08": "NGS",
"Michael_Jordan_A10": "W2205770",
"Michael_Jordan_B10": "W2205770",
...
"DNA_F12": "No",
}
Optimised way of creating same dictionary
thisdict = dict(
(lambda x: ('_'.join(x[4:6]), x[3]))(s.split('_'))
for s in lst
)
Using reduce function
reduce(lambda x, y: x.update({ '_'.join(y.split('_')[4:6]): y.split('_')[3] }) or x, lst, {})
Try this:
lst = ['MLID_D_08_NGS_34_H08.fsa',
'MLID_D_17_W2205770_Michael_Jordan_A10.fsa',
'MLID_D_18_W2205770_Michael_Jordan_B10.fsa',
'MLID_D_19_W2205768_Maradona_Guti_C10.fsa',
'MLID_D_20_W2205768_Maradona_Guti_D10.fsa',
'MLID_D_38_No_DNA_F12.fsa']
dic = {}
for name in lst:
name = name.split(".")[0].split("_")
dic["_".join(name[4:])] = name[3]
print(dic)
This code may help you.
lst = ['MLID_D_08_NGS_34_H08.fsa',
'MLID_D_17_W2205770_Michael_Jordan_A10.fsa',
'MLID_D_18_W2205770_Michael_Jordan_B10.fsa',
'MLID_D_19_W2205768_Maradona_Guti_C10.fsa',
'MLID_D_20_W2205768_Maradona_Guti_D10.fsa',
'MLID_D_38_No_DNA_F12.fsa']
lst = [a.split('.') for a in lst] # split by .
dict_ = {}
for l in lst:
k = '_'.join(l[0].split('_')[4:]) # make key
v = l[0].split('_')[3] # make value
dict_[k]=v # add value to dict
print(dict_)
OUTPUT
{'34_H08': 'NGS',
'Michael_Jordan_A10': 'W2205770',
'Michael_Jordan_B10': 'W2205770',
'Maradona_Guti_C10': 'W2205768',
'Maradona_Guti_D10': 'W2205768',
'DNA_F12': 'No'}
As #matszwecja indicated s.split('_') is the way to go.
You can access different parts of the split as follows:
lst = ['MLID_D_08_NGS_34_H08.fsa',
'MLID_D_17_W2205770_Michael_Jordan_A10.fsa',
'MLID_D_18_W2205770_Michael_Jordan_B10.fsa',
'MLID_D_19_W2205768_Maradona_Guti_C10.fsa',
'MLID_D_20_W2205768_Maradona_Guti_D10.fsa',
'MLID_D_38_No_DNA_F12.fsa']
thisdict = {s.split('_')[4] + '_' + s.split('_')[5].split('.')[0]: s.split('_')[3] for s in lst}

how can i loop like this but getting everything instead of only the 1st one

i want loop like this but getting everything instead of only the 1st one.
from collections import OrderedDict
myList = OrderedDict(
{
'ID': ["1stID", "2ndID","3ndID"], 'ChannelID': ["1stChannel", "2ndChannel","3ndChannel"]
})
first_values = [v[0] for v in myList.values()]
print(first_values)
OUTPUT
['1stID', '1stChannel']
instead of
['1stID', '1stChannel']
DESIRED OUTPUT:
['1stID', '1stChannel']
['2stID', '2stChannel']
['3stID', '3stChannel']
You can use zip() to combine two list and get the combined pairs, as follows:
from collections import OrderedDict
myList = OrderedDict(
{
'ID': ["1stID", "2ndID", "3ndID"],
'ChannelID': ["1stChannel", "2ndChannel", "3ndChannel"]
})
pairs = zip(myList['ID'], myList['ChannelID'])
# list(pairs) -> [('1stID', '1stChannel'), ('2ndID', '2ndChannel'), ('3ndID', '3ndChannel')]
for pair in pairs:
print(list(pair))
Result:
['1stID', '1stChannel']
['2ndID', '2ndChannel']
['3ndID', '3ndChannel']
Other method (if you don't want to use key names):
from collections import OrderedDict
myList = OrderedDict(
{
"ID": ["1stID", "2ndID", "3ndID"],
"ChannelID": ["1stChannel", "2ndChannel", "3ndChannel"],
}
)
for a in zip(*myList.values()):
print(a) # or list(a) for lists instead of tuples
Prints:
('1stID', '1stChannel')
('2ndID', '2ndChannel')
('3ndID', '3ndChannel')
You misunderstood the structure you are building so you are not accessing it correctly.
mylist is a 2 element dictionary. each of the element are lists of length 3.
There is no connection between the positional elements of each other than the position.
See code below how I extracted and printed the data.
There may be an idiomatic way to do this in python more cleanly
but this served to show the structure clearly.
from collections import OrderedDict
myList = OrderedDict(
{
'ID': ["1stID", "2ndID", "3ndID"],
'ChannelID': ["1stChannel", "2ndChannel", "3ndChannel"]
})
first_values = [v[0] for v in myList.values()]
print(first_values)
#
# print out the values of the objects in the list
for v in myList.values():
print(v)
# extract the two lists
vid, vchan = myList.values()
# print out the whole list in one statement
print("all of vid ", vid)
print("all of vchan ", vchan)
# print out the element of the lists position by position
for i in range(len(vid)):
print(i, "th list item ", vid[i], vchan[i])

Using a for-loop to convert list to 2d dictionary

I am having trouble converting a 2d list into a 2d dictionary. I haven't worked much with 2d dictionaries prior to this so please bear with me. I am just wondering why this keeps pulling up a KeyError. In this quick example I would want the dictionary to look like {gender: { name: [food, color, number] }}
2dList = [['male','josh','chicken','purple','10'],
['female','Jenny','steak','blue','11']]
dict = {}
for i in range(len(2dList)):
dict[2dList[i][0]][2dList[i][1]] = [2dList[i][2], 2dList[i][3], 2dList[i][4]]
I keep getting the error message: KeyError: 'male'. I know this is how you add keys for a 1d dictionary, but am unsure regarding 2d dictionaries. I always believed it was:
dictionary_name[key1][key2] = value
You can try this :) It will also work if you have more than one male or female in your List
List = [['male','josh','chicken','purple','10'],
['female','Jenny','steak','blue','11']]
d = {}
for l in List:
gender = l[0]
name = l[1]
food = l[2]
color = l[3]
number = l[4]
if gender in d: # if it exists just add new name by creating new key for name
d[gender][name] = [food,color,number]
else: # create new key for gender (male/female)
d[gender] = {name:[food,color,number]}
You are attempting to build a nested dictionary. But are not explicitly initializing the second-layer dictionaries. You need to do this each time, a new key is encountered. Btw, 2dlist is an erroneous way to declare variables in python. This should work for you:
dList = [['male','josh','chicken','purple','10'],
['female','Jenny','steak','blue','11']]
dict = {}
for i in range(len(dList)):
if not dList[i][0] in dict.keys():
dict[dList[i][0]] = {}
dict[dList[i][0]][dList[i][1]] = [dList[i][2], dList[i][3], dList[i][4]]
print(dict)
To get more or less "sane" result use the following (list of dictionaries, each dict is in format {gender: { name: [food, color, number] }}):
l = [['male','josh','chicken','purple','10'], ['female','Jenny','steak','blue','11']]
result = [{i[0]: {i[1]:i[2:]}} for i in l]
print(result)
The output:
[{'male': {'josh': ['chicken', 'purple', '10']}}, {'female': {'Jenny': ['steak', 'blue', '11']}}]
You are getting a KeyError because you are trying to access a non-existing entry on the dictionary with male as the key
You can use defaultdict instead of dict.
from collections import defaultdict
2dList = [['male','josh','chicken','purple','10'],
['female','Jenny','steak','blue','11']]
dict = defaultdict(list)
for i in range(len(2dList)):
dict[2dList[i][0]][2dList[i][1]] = [2dList[i][2], 2dList[i][3], 2dList[i][4]]
Try this
twodList = [['male','josh','chicken','purple','10'],
['female','Jenny','steak','blue','11']]
dic = {twodList[i][0]: {twodList[i][1]: twodList[i][2:]} for i in range(len(twodList))}
As someone mentioned in the comments, you cannot have a variable starting with a number.
list1=[['male','josh','chicken','purple','10'],['female','Jenny','steak','blue','11'],['male','johnson','chicken','purple','10'],['female','jenniffer','steak','blue','11']]
dict = {}
for i in range(len(list1)):
if list1[i][0] in dict:
if list1[i][1] in dict[list1[i][0]]:
dict[list1[i][0]][list1[i][1]] = [list1[i][2], list1[i][3], list1[i][4]]
else:
dict[list1[i][0]][list1[i][1]] = {}
dict[list1[i][0]][list1[i][1]] = [list1[i][2], list1[i][3], list1[i][4]]
else:
dict[list1[i][0]] = {}
if list1[i][1] in dict[list1[i][0]]:
dict[list1[i][0]][list1[i][1]] = [list1[i][2], list1[i][3], list1[i][4]]
else:
dict[list1[i][0]][list1[i][1]] = {}
dict[list1[i][0]][list1[i][1]] = [list1[i][2], list1[i][3], list1[i][4]]
print dict
Above one gives below output:
{"male":{"josh":["chicken","purple","10"],"johnson":["chicken","purple","10"]},"female":{"jenniffer":["steak","blue","11"],"Jenny":["steak","blue","11"]}}

Sort python list into dictionary of lists, based on property in list

I'm trying to sort a list of objects in python into a dictionary of lists via a property of the objects in the original list
I've done it below, but this feels like something I should be able to do using a dictionary comprehension?
for position in totals["positions"]:
if not hasattr(totals["positions_dict"], position.get_asset_type_display()):
totals["positions_dict"][position.get_asset_type_display()] = []
totals["positions_dict"][position.get_asset_type_display()].append(position)
Some self improvements
totals["positions_dict"] = {}
for position in totals["positions"]:
key = position.get_asset_type_display()
if key not in totals["positions_dict"]:
totals["positions_dict"][key] = []
totals["positions_dict"][key].append(position)
You could use itertools.groupby and operator.methodcaller in a dict comprehension:
from operator import methodcaller
from itertools import groupby
key = methodcaller('get_asset_type_display')
totals["positions_dict"] = {k: list(g) for k, g in groupby(sorted(totals["positions"], key=key), key=key)}
Using a defaultdict as suggested by #Jean-FrançoisFabre allows you to do it with a single call to get_asset_type_display() in one loop:
from collections import defaultdict
totals["positions_dict"] = defaultdict(list)
for position in totals["positions"]:
totals["positions_dict"][position.get_asset_type_display()].append(position)
Haven't tested this, because I don't have your data.
And I think it's rather ugly, but it just may work:
totals ['positions_dict'] = {
key: [
position
for position in totals ['positions']
if position.get_asset_type_display () == key
]
for key in {
position.get_asset_type_display ()
for position in totals ['positions']
}
}
But I would prefer something very simple, and avoid needless lookups / calls:
positions = totals ['positions']
positions_dict = {}
for position in positions:
key = position.get_asset_type_display ()
if key in positions_dict:
positions_dict [key] .append (position)
else:
positions_dict [key] = [position]
totals ['positions_dict'] = positions_dict
positions = totals ['positions']

Categories

Resources