create a specific python dictionary from 2 lists - python

I have the following data:
fsm_header = ['VLAN_ID', 'NAME', 'STATUS']
fsm_results = [['1', 'default', 'active'],
['2', 'VLAN0002', 'active'],
['3', 'VLAN0003', 'active']]
I want to create a specific dictionary like this:
{'VLAN_ID':['1','2','3'],
'NAME':['default','VLAN0002','VLAN0003'],
'STATUS':['active','active','active']}
I'm having trouble finding the right combination, as the one I'm using:
dict(zip(fsm_header, row)) for row in fsm_results
gives me another type of useful output, but not the one I mentioned above.
I would prefer to see something without using the zip function, but even with zip is ok.

You need to unpack and zip fsm_results too:
out = {k:list(v) for k,v in zip(fsm_header, zip(*fsm_results))}
Output:
{'VLAN_ID': ['1', '2', '3'],
'NAME': ['default', 'VLAN0002', 'VLAN0003'],
'STATUS': ['active', 'active', 'active']}
If you don't mind tuple as values; then you could use:
out = dict(zip(fsm_header, zip(*fsm_results)))
Output:
{'VLAN_ID': ('1', '2', '3'),
'NAME': ('default', 'VLAN0002', 'VLAN0003'),
'STATUS': ('active', 'active', 'active')}
You could also write the same thing using dict.setdefault:
out = {}
for lst in fsm_results:
for k, v in zip(fsm_header, lst):
out.setdefault(k, []).append(v)

Related

Flatten list of list into list for dictionary

I have a dictionary that looks like this:
{'data': [['748','','285','102','76024']]}
and I want to flatten the lists to look like this:
{'data': ['748','','285','102','76024']}
I have tried this from here:
[item for sublist in data.items() for item in sublist]
but it gives me:
['data',
[['748',
'',
'285',
'102',
'76024',
'88',
'3',
'89%831',
'77%',
'',
'68%632',
'19%177',
'13%120']]]
Based on the title, I noticed that you might have list of lists in each item in your dictionary. Using itertools.chain() you can merge multiple lists into one:
import itertools
data = {'data': [['748','','285','102','76024']]}
data1 = {'data': [['748','','285','102','76024'], ['12', '13', '14']]}
output = {k: list(itertools.chain(*v)) for k,v in data.items()}
output1 = {k: list(itertools.chain(*v)) for k,v in data1.items()}
Output:
# Output
{'data': ['748', '', '285', '102', '76024']}
# Output1
{'data': ['748', '', '285', '102', '76024', '12', '13', '14']}

formatting dictionary structure in python

I have an input list of the form:
d=[{'CLIENT': ['A','B','C']},{'ROW':['1','2','3']},{'KP':['ROM','MON','SUN']}]
I want the output to look like:
S=[{'CLIENT':'A','ROW':'1','KP':'ROM'},
{'CLIENT':'B','ROW':'2','KP':'MON'},
{'CLIENT':'C','ROW':'3','KP':'SUN'},]
How can i do this in python?
the input element dictionaries' keys may change, so I don't want to hardcode them in the code as well.
With a little cheating by letting pandas do the work:
Setup:
from collections import ChainMap
import pandas as pd
d = [{'CLIENT': ['A','B','C']},{'ROW':['1','2','3']},{'KP':['ROM','MON','SUN']}]
Solution:
result = pd.DataFrame(dict(ChainMap(*d))).to_dict(orient='records')
Result:
[{'KP': 'ROM', 'ROW': '1', 'CLIENT': 'A'},
{'KP': 'MON', 'ROW': '2', 'CLIENT': 'B'},
{'KP': 'SUN', 'ROW': '3', 'CLIENT': 'C'}]
Manually it would look like this
S=[{} for i in range(len(d))]
i = 0
for dict in d:
for k, v in dict.items(): # Always 1
for value in v:
S[i][k]=value
i+=1
i=0
print(S)
Extract the key from the each dictionary and the values, then zip() them together into a new dict():
data = [{'CLIENT': ['A', 'B', 'C']}, {'ROW': ['1', '2', '3']}, {'KP': ['ROM', 'MON', 'SUN']}]
new_keys = [list(d.keys())[0] for d in data]
new_values = zip(*[val for d in data for val in d.values()])
s = [dict(zip(new_keys, val)) for val in new_values]
print(s)
Output:
[{'CLIENT': 'A', 'ROW': '1', 'KP': 'ROM'},
{'CLIENT': 'B', 'ROW': '2', 'KP': 'MON'},
{'CLIENT': 'C', 'ROW': '3', 'KP': 'SUN'}]
This is another way of doing it, by making use of the builtin zip() function a couple of times, and the chain() function of the itertools module.
The idea is to use zip() first to group together the lists' items (('A', '1', 'ROM'), ('B', '2', 'MON'), ('C', '3', 'SUN')) as we desire, and the keys of each dictionary ('CLIENT', 'ROW', 'KP')).
Then, we can use a list comprehension, iterating over the just created values list, and zipping its content together with the keys tuple, to finally produce the dictionaries that will be stored within the s list
from itertools import chain
d = [{'CLIENT': ['A','B','C']},{'ROW':['1','2','3']},{'KP':['ROM','MON','SUN']}]
keys, *values = zip(*[chain(dict_.keys(), *dict_.values()) for dict_ in d])
s = [dict(zip(keys, tuple_)) for tuple_ in values]
The content of s will be:
[
{'CLIENT': 'A', 'ROW': '1', 'KP': 'ROM'},
{'CLIENT': 'B', 'ROW': '2', 'KP': 'MON'},
{'CLIENT': 'C', 'ROW': '3', 'KP': 'SUN'}
]

Grouping values to a list in dict

While reading a csv file using csv.DictReader
I get
[{'id': 1, 'status1': '1', 'status2': '2', 'status3': '3' }]
How can I manuplate while reading or later to get:
[{'id': 1, 'status': ['1', '2', '3']}]
TLDR;
I want to group similar fields into a list.
and/or - how can i do this in pandas pd.read_csv() too?
Thanks in advance!
If it is certain that the only fields you want to group are those who end with digits, you can use a regex to identify them, and append their corresponding values to a list:
import re
def compact_dict(d):
compact = {}
for key, value in d.items():
# a group containing anything, followed by at least one digit
m = re.match(r'(.*)\d+', key)
if m:
# the key that we use is the original one without the final digits
compact.setdefault(m.group(1), []).append(value)
else:
# not part of a group of similar keys, we just store the key:value pair
compact[key] = value
return compact
data = [{'id': 1, 'status1': '1', 'status2': '2', 'status3': '3' }]
out = [compact_dict(d) for d in data]
print(out)
# [{'id': 1, 'status': ['1', '2', '3']}]

Python merge list concating unique values as comma seperated

I am trying to get this to work.
Here is my data:
data.csv
id,fname,lname,education,gradyear,attributes
1,john,smith,mit,2003,qa
1,john,smith,harvard,207,admin
1,john,smith,ft,212,master
2,john,doe,htw,2000,dev
Trying to use this code. Found this code on the Internet, don't fully understand it.
from itertools import groupby
import csv
import pprint
t = csv.reader(open('data.csv'))
t = list(t)
def join_rows(rows):
def join_tuple(tup):
for x in tup:
if x:
return x
else:
return x
return [join_tuple(x) for x in zip(*rows)]
for name, rows in groupby(sorted(t), lambda x:x[0]):
print join_rows(rows)
However, it does not merge unique values as comma separated.
The output is:
['1', 'john', 'smith', 'ft', '212', 'master']
['2', 'john', 'doe', 'htw', '2000', 'dev']
['id', 'fname', 'lname', 'education', 'gradyear', 'attributes']
How can I make it like:
['1', 'john', 'smith', 'mit,harvard,ft', '2003,207,212', 'qa,admin,master']
['2', 'john', 'doe', 'htw', '2000', 'dev']
['id', 'fname', 'lname', 'education', 'gradyear', 'attributes']
If there are more entries for the same column, it should also work. Should not be limited to 3 rows.
Grrrrr .... anybody have tips or ideas?
Thanks in advance!
You can change the definition of join_rows to
import itertools
def join_rows(rows):
return [(e[0] if i < 3 else ','.join(e)) for (i, e) in enumerate(zip(*rows))]
What this does is to zip all entries belonging to the same id into tuples. For the first 3 tuples, the first item is returned; for the latter, they are joined by commas.
['1', 'john', 'smith', 'ft,harvard,mit', '212,207,2003', 'master,admin,qa']
['2', 'john', 'doe', 'htw', '2000', 'dev']
['id', 'fname', 'lname', 'education', 'gradyear', 'attributes']

Reconstruct the list of dict in python but the result is not in order

list_1 = [{'1': 'name_1', '2': 'name_2', '3': 'name_3',},
{'1': 'age_1', '2': 'age_2' ,'3': 'age_3',}]
I want to manipulate this list so that the dicts contain all the attributes for a particular ID. The ID itself must form part of the resulting dict. An example output is shown below:
list_2 = [{'id' : '1', 'name' : 'name_1', 'age': 'age_1'},
{'id' : '2', 'name' : 'name_2', 'age': 'age_2'},
{'id' : '3', 'name' : 'name_3', 'age': 'age_3'}]
Then I did following:
>>> list_2=[{'id':x,'name':list_1[0][x],'age':list_1[1][x]} for x in list_1[0].keys()]
Then it gives:
>>> list_2
[{'age': 'age_1', 'id': '1', 'name': 'name_1'},
{'age': 'age_3', 'id': '3', 'name': 'name_3'},
{'age': 'age_2', 'id': '2', 'name': 'name_2'}]
But I don't understand why 'id' is showing in the second position while 'age' showing first?
I tried other ways but the result is the same. Any one can help to figure it out?
To keep the order, you should use an ordered dictionary. Using your sample:
new_list = [OrderedDict([('id', x), ('name', list_1[0][x]), ('age', list_1[1][x])]) for x in list_1[0].keys()]
Printing the ordered list...
for d in new_list:
print(d[name], d[age])
name_1 age_1
name_3 age_3
name_2 age_2
Try using an OrderedDict:
list_1 = [collections.OrderedDict([('1','name_1'), ('2', 'name_2'), ('3', 'name_3')]),
collections.OrderedDict([('1','age_1'),('2','age_2'),('3', 'age_3')])]
list_2=[collections.OrderedDict([('id',x), ('name',list_1[0][x]), ('age', list_1[1][x])])
for x in list_1[0].keys()]
This is more likely to preserve the order you want. I am still new to Python, so this may not be super Pythonic, but I think it will work.
output -
In [24]: list( list_2[0].keys() )
Out[24]: ['id', 'name', 'age']
Docs:
https://docs.python.org/3/library/collections.html#collections.OrderedDict
Examples:
https://pymotw.com/2/collections/ordereddict.html
Getting the constructors right:
Right way to initialize an OrderedDict using its constructor such that it retains order of initial data?

Categories