I have a dictionary as follows:
a = {'name': 'Test', 'lastName': 'Test', 'scores': ['1', '2'], 'subjects': ['te','re'] }
I have tried nested loops, but I'm not sure if that's the best approach.
As an output I need a list of dictionaries for each score and subject :
result1 = { 'name':'Test', 'lastName': 'Test', 'score': '1', 'subjects': 'te'}
result2 = { 'name':'Test', 'lastName': 'Test', 'score': '2', 'subjects': 're'}
How to best iterate through the lists and create such dictionary? The number of scores and subjects will always match.
Any help would be appreciated.
Here is a function which unzip your dictionary.
We first use next to find some list value in the dictionary, its length is the expected output size.
Note that this will fail if the dictionary contains no list at all.
def unzip_dict(d):
# Find one of the list in the dictionary to read its length
length = len(next(value for value in d.values() if isinstance(value, list)))
output = []
# Unzip the dictionary
for i in range(length):
output.append({k: v[i] if isinstance(v, list) else v for k, v in d.items()})
return output
a = {'name': 'Test', 'lastName': 'Test', 'scores': ['1', '2'], 'subjects': ['te', 're']}
print(unzip_dict(a))
Output
[{'lastName': 'Test', 'name': 'Test', 'scores': '1', 'subjects': 'te'},
{'lastName': 'Test', 'name': 'Test', 'scores': '2', 'subjects': 're'}]
Try this:
# setup data
a = {'name': 'Test', 'lastName': 'Test', 'scores': ['1', '2'], 'subjects': ['te','re'] }
# create list of dictionary
out_list = []
for value in a.get('scores'):
for item in a.get('subjects'):
out_list.append({'name': 'Test', 'lastName': 'Test', 'scores':value, 'subjects':item})
Output:
{'name': 'Test', 'lastName': 'Test', 'scores': '1', 'subjects': 'te'}
{'name': 'Test', 'lastName': 'Test', 'scores': '1', 'subjects': 're'}
{'name': 'Test', 'lastName': 'Test', 'scores': '2', 'subjects': 'te'}
{'name': 'Test', 'lastName': 'Test', 'scores': '2', 'subjects': 're'}
You don't need nested for loops, a single for loop is sufficient:
def foo(a):
finarr=[]
for i in range(len(a['scores'])):
fnarr={}
fnarr['name']=a['name']
fnarr['lastName']=a['lastName']
fnarr['score']=a['scores'][i]
fnarr['subject']=a['subjects'][i]
finarr.append(fnarr)
return finarr
Output:
[{'name': 'Test', 'lastName': 'Test', 'score': '1', 'subject': 'te'},
{'name': 'Test', 'lastName': 'Test', 'score': '2', 'subject': 're'}]
you can try this:
res1 = {}
res2= {}
for k,v in a.items():
if(k == "scores"):
res1[k] = v[0]
res2[k] = v[1]
elif(k=="subjects"):
res1[k] = v[0]
res2[k] = v[1]
else:
res1[k] = v
res2[k] = v
print(res1)
print(res2)
you can also take a look to defaultdict i think that would help you on your Task
You can utilize zip to attach scores and subjects to each other and then add it to a new list.
d = {'name': 'Test', 'lastName': 'Test', 'scores': ['1', '2'], 'subjects': ['te','re'] }
template = {'name': d['name'], 'lastName': d['lastName']}
res = []
for subject, score in zip(d['subjects'], d['scores']):
template.update({'subjects': subject, 'scores': score})
res.append(template)
print(res)
Related
I've trying to convert list to tuples to customized list to dictionaries. I'm able toto divide admin, pack owner, submitter, consumer and read only. Please check below code and output
from collections import defaultdict
role_details = ['po','sub', 'cons', 'admin','read']
lst = [('name1', 'email1', 'psid1', 'new1', 11, '1', 'po'),
('name2', 'email2', 'psid2', 'new2', 12, '2', 'sub'),
('name3', 'email3', 'psid3', 'new3', 13, '3', 'sub'),
('name4', 'email4', 'psid4', 'new4', 14, '4', 'po'),
('name5', 'email5', 'psid5', 'new5', 15, '5', 'cons')]
by_role = defaultdict(list)
for name, email, psid, new, id1, id2, role_name in lst:
by_role[role_name].append({"name": name, "email": email, "psid": psid})
print({"add_sub": dict(by_role)})
output:
{'add_sub':
{'po': [{'name': 'name1', 'email': 'email1', 'psid': 'psid1'}, {'name': 'name4', 'email': 'email4', 'psid': 'psid4'}],
'sub': [{'name': 'name2', 'email': 'email2', 'psid': 'psid2'}, {'name': 'name3', 'email': 'email3', 'psid': 'psid3'}],
'cons': [{'name': 'name5', 'email': 'email5', 'psid': 'psid5'}]
}
}
but if any of the role details record not exit in the lst i'm trying to pass an empty list. Please check the expected output
expected output:
{'add_sub':
{'admin': [],
'po': [{'name': 'name1', 'email': 'email1', 'psid': 'psid1'}, {'name': 'name4', 'email': 'email4', 'psid': 'psid4'}],
'read': [],
'sub': [{'name': 'name2', 'email': 'email2', 'psid': 'psid2'}, {'name': 'name3', 'email': 'email3', 'psid': 'psid3'}],
'cons': [{'name': 'name5', 'email': 'email5', 'psid': 'psid5'}]
}
}
I'm new to python plz suggest me with logic. thank you
You can also create the dict with all the keys you need beforehand. In this case you don't even need the defaultdict, unless you need its functionality later.
#from collections import defaultdict
role_details = ['pack owner','submitter', 'consumer', 'admin','read only']
lst = [('name1', 'email1', 'psid1', 'new1', 11, '1', 'pack owner'),
('name2', 'email2', 'psid2', 'new2', 12, '2', 'submitter'),
('name3', 'email3', 'psid3', 'new3', 13, '3', 'submitter'),
('name4', 'email4', 'psid4', 'new4', 14, '4', 'pack owner'),
('name5', 'email5', 'psid5', 'new5', 15, '5', 'consumer')]
#by_role = defaultdict(list)
by_role = {k: [] for k in role_details}
for name, email, psid, new, id1, id2, role_name in lst:
by_role[role_name].append({"name": name, "email": email, "psid": psid})
print({"add_sub": by_role})
{'add_sub':
{'pack owner': [{'name': 'name1', 'email': 'email1', 'psid': 'psid1'}, {'name': 'name4', 'email': 'email4', 'psid': 'psid4'}],
'submitter': [{'name': 'name2', 'email': 'email2', 'psid': 'psid2'}, {'name': 'name3', 'email': 'email3', 'psid': 'psid3'}],
'consumer': [{'name': 'name5', 'email': 'email5', 'psid': 'psid5'}],
'admin': [],
'read only': []}
}
Also note that you don't need the dict() call in the print, since by_role is already a dict.
If you do need the defaultdict, you can do the same thing with this line:
from collections import defaultdict
# ...code...
by_role = defaultdict(list, {k: [] for k in role_details})
by_role is a defaultdict(list), so you'll get an empty list if you try to access the by_role['admin'] or by_role['read only'].
In fact, all you need to do is try to access those keys once, and they get added to the defaultdict, so you can iterate over role_details and do that:
for name, email, psid, new, id1, id2, role_name in lst:
by_role[role_name].append({"name": name, "email": email, "psid": psid})
for role_name in role_details:
_ = by_role[role_name] # Try to access every key, and don't do anything with it.
Then, you should have your expected output:
{'add_sub': {
'pack owner': [
{'name': 'name1', 'email': 'email1', 'psid': 'psid1'},
{'name': 'name4', 'email': 'email4', 'psid': 'psid4'}
],
'submitter': [
{'name': 'name2', 'email': 'email2', 'psid': 'psid2'},
{'name': 'name3', 'email': 'email3', 'psid': 'psid3'}
],
'consumer': [{'name': 'name5', 'email': 'email5', 'psid': 'psid5'}],
'admin': [],
'read only': []
}
}
This is my json :
{'1': {'name': 'poulami', 'password': 'paul123', 'profession': 'user', 'uid': 'poulamipaul'}, '2': {'name': 'test', 'password': 'testing', 'profession': 'tester', 'uid': 'jarvistester'}}
I want to get a list of all the values of name.
What should be my code in python
d.values gives all the values, then you can get the attribute name of each value.
d = {'1': {'name': 'poulami', 'password': 'paul123', 'profession': 'user', 'uid': 'poulamipaul'}, '2': {'name': 'test', 'password': 'testing', 'profession': 'tester', 'uid': 'jarvistester'}}
[i['name'] for i in d.values()]
['poulami', 'test']
Also note that d.values returns a generator and not a list so to convert to list use list(d.values())
That is not JSON format. It is a Python Dictionary.
Iterate over the values of the dictionary(d.values()) and get the name from each item.
d = {'1': {'name': 'poulami', 'password': 'paul123', 'profession': 'user', 'uid': 'poulamipaul'}, '2': {'name': 'test', 'password': 'testing', 'profession': 'tester', 'uid': 'jarvistester'}}
names_list = []
for i in d.values():
names_list.append(i['name'])
names_list = ['poulami', 'test']
I have the following three dictionaries in an array:
items = [
{
'FirstName': 'David',
'LastName': 'Smith',
'Language': set(['en'])
},
{
'FirstName': 'David',
'LastName': 'Smith',
'Language': set(['fr'])
},
{
'FirstName': 'Bob',
'LastName': 'Jones',
'Language': set(['en'])
} ]
I want to merge together these dictionaries if the two dictionaries are the same minus the specified key: and add that key together. If using the "Language" key it would merge the array into the following:
[ {
'FirstName': 'David',
'LastName': 'Smith',
'Language': set(['en','fr'])
},{
'FirstName': 'Bob',
'LastName': 'Jones',
'Language': set(['en'])
} ]
Here is what I'm currently doing:
from copy import deepcopy
def _merge_items_on_field(items, field):
'''Given an array of dicts, merge the
dicts together if they are the same except for the 'field'.
If merging dicts, add the unique values of that field together.'''
items = deepcopy(items)
items_merged_on_field = []
for num, item in enumerate(items):
# Remove that key/value from the dict
field_value = item.pop(field)
# Get an array of items *without* that field to compare against
items_without_field = deepcopy(items_merged_on_field)
map(lambda d: d.pop(field), items_without_field)
# If the dict item is found ("else"), add the fields together
# If not ("except"), then add in the dict item to the array
try:
index = items_without_field.index(item)
except ValueError:
item[field] = field_value
items_merged_on_field.append(item)
else:
items_merged_on_field[index][field] = items_merged_on_field[index][field].union(field_value)
return items_merged_on_field
>>> items = [{'LastName': 'Smith', 'Language': set(['en']), 'FirstName': 'David'}, {'LastName': 'Smith', 'Language': set(['fr']), 'FirstName': 'David'}, {'LastName': 'Jones', 'Language': set(['en']), 'FirstName': 'Bob'}]
>>> _merge_items_on_field(items, 'Language')
[{'LastName': 'Smith', 'Language': set(['fr', 'en']), 'FirstName': 'David'}, {'LastName': 'Jones', 'Language': set(['en']), 'FirstName': 'Bob'}]
This seems a bit complicated -- is there a better way to do this?
There are a couple of ways of doing this. The most painless method to my knowledge utilises the pandas library—in particular, a groupby + apply.
import pandas as pd
merged = (
pd.DataFrame(items)
.groupby(['FirstName', 'LastName'], sort=False)
.Language
.apply(lambda x: set.union(*x))
.reset_index()
.to_dict(orient='records')
)
print(merged)
[
{'FirstName': 'David', 'LastName': 'Smith', 'Language': {'en', 'fr'}},
{'FirstName': 'Bob', 'LastName': 'Jones', 'Language': {'en'}}
]
The other method (that I mentioned) uses itertools.groupby, but seeing as you have 30 columns to group on, I'd just recommend sticking to pandas.
If you want to turn this into a function,
def merge(items, field):
df = pd.DataFrame(items)
columns = df.columns.difference([field]).tolist()
return (
df.groupby(columns, sort=False)[field]
.apply(lambda x: set.union(*x))
.reset_index()
.to_dict(orient='records')
)
merged = merge(items, 'Language')
print(merged)
[
{'FirstName': 'David', 'LastName': 'Smith', 'Language': {'en', 'fr'}},
{'FirstName': 'Bob', 'LastName': 'Jones', 'Language': {'en'}}
]
You can use itertools.groupby:
import itertools
d = [{'FirstName': 'David', 'LastName': 'Smith', 'Language': {'en'}}, {'FirstName': 'David', 'LastName': 'Smith', 'Language': {'fr'}}, {'FirstName': 'Bob', 'LastName': 'Jones', 'Language': {'en'}}]
v = [[a, list(b)] for a, b in itertools.groupby(sorted(d, key=lambda x:x['FirstName']), key=lambda x:x['FirstName'])]
final_dict = [{**{'FirstName':a}, **{'LastName':(lambda x:[list(set(x)), x[0]][len(set(x)) == 1])([i['LastName'] for i in b])}, **{'Language':set([list(i['Language'])[0] for i in b])}} for a, b in v]
Output:
[{'FirstName': 'Bob', 'LastName': 'Jones', 'Language': {'en'}}, {'FirstName': 'David', 'LastName': 'Smith', 'Language': {'en', 'fr'}}]
If pandas is not an option:
from itertools import groupby
from functools import reduce
arr = [
{'FirstName': 'David', 'LastName': 'Smith', 'Language': set(['en'])},
{'FirstName': 'David', 'LastName': 'Smith', 'Language': set(['fr'])},
{'FirstName': 'David', 'LastName': 'Jones', 'Language': set(['sp'])}
]
def reduce_field(items, field, op=set.union, sort=False):
def _key(d):
return tuple((k, v) for k, v in d.items() if k != field)
if sort:
items = sorted(items, key=_key)
res = []
for k, g in groupby(items, key=_key):
d = dict(k)
d[field] = reduce(op, (el[field] for el in g))
res.append(d)
return res
reduce_field(arr, 'Language')
You can try it manually :
new_dict={}
#
#
#
d = [{'FirstName': 'David', 'LastName': 'Smith', 'Language': {'en'}},
{'FirstName': 'David', 'LastName': 'Smith', 'Language': {'fr'}},
{'FirstName': 'Bob', 'LastName': 'Jones', 'Language': {'en'}}]
for i in d:
if (i['FirstName'],i['LastName']) not in new_dict:
new_dict[(i['FirstName'],i['LastName'])]=i
else:
new_dict[(i['FirstName'],i['LastName'])]['Language']=set(list(new_dict[(i['FirstName'],i['LastName'])]['Language'])+list(i['Language']))
print(new_dict.values())
output:
# dict_values([{'FirstName': 'Bob',
# 'LastName': 'Jones',
# 'Language': {'en'}},
# {'FirstName': 'David',
# 'LastName': 'Smith',
# 'Language': {'fr', 'en'}}])
I want to combine longitude and latitude to
{latlon: '40.33333,-79.34343'}
the entire JSON is in variable data = jsonData
I want to remove original key-value pair
{
'locale': 'en_US',
'timezone': '-7',
'id': '13',
'agerangemin': '21',
'verified': 'true',
'coverimageurl': 'scontent.xx.fbcdn/t31.0-0/p480x480/13063482_1183967848280764_1411489384515766669_o.jpg',
'tagline': 'Veggien',
'lastupdated': '1462341401',
'fbupdated_time': '2016-03-30T00:38:48+0000',
'lname': 'Kulkarni',
'fname': 'Nikhil',
'email': 'nikhilhk.usa#gmail.com',
'latitude': '40.333333',
'longitude': '-79.34343',
'displayname': 'Nikhil Kulkarni',
'fbprofileid': '1121344884543061',
'profileimageurl': 'scontent.xx.fbcdn/hprofile-xft1/v/t1.0-1/p100x100/10423743_952350738109144_964810479230145631_n.jpg?oh=71f7e953dbbf8e2f1d9f22418f7888b2&oe=579F4A36',
'link': 'facebook/app_scoped_user_id/1121344884543061/',
'diet': 'Vegetarian',
'dietsinceyear': '1966',
'gender': 'M',
'vegstory': '',
'shortdescription': 'Just like that',
'categoryids': '',
'reasonforveg': 'Religious'
}
data['latlong'] = data['latitude'] + ',' + data['longitude']
del data['latitude']
del data['longitude']
Can be done in one line.
>>> dic = {'latitude': '40.333333', 'longitude': '-79.34343'}
>>>
>>> dic['latlon'] = "{0},{1}".format(dic.pop('latitude'),dic.pop('longitude'))
>>> dic
{'latlon': '40.333333,-79.34343'}
To understand how dic.pop() work, see this.
>>> json_data['latlon'] = ','.join(json_data[k] for k in ('latitude', 'longitude'))
>>> json_data['latlon']
'40.333333,-79.34343'
Note that this will preserve the original key-value pair.
UPDATE:
If you want to remove the original key-value pair use pop method:
>>> json_data['latlon'] = ','.join(json_data.pop(k) for k in ('latitude', 'longitude'))
>>> json_data['latlon']
'40.333333,-79.34343'
How to split string values across a list of dictionaries, so that each part of the split string is in it's own dictionary?
For example:
lst = [{item:'321,121,343','name':'abby','amount':'400'},{item:'111,222,333','name':'chris','amount':'500'}]
I'd like each part of the item key-value pair to be in its own dictionary
Desired_List = [{item:'321','name':'abby','amount':'400'},{item:'121','name':'abby','amount':'400'},{item:'343','name':'abby','amount':'400'},{item:'111','name':'chris','amount':'500'},{item:'222','name':'chris','amount':'500'},{item:'333','name':'chris','amount':'500'}]
I've tried this with no luck:
[li.update({li['item']:spl}) for li in lst for spl in li['item'].split(',')]
return Li
def unpack_dict(d, field, unpack):
packed = d.pop(field)
for item in unpack(packed):
result = d.copy()
result[field] = item
yield result
lst = [
{'item':'321,121,343','name':'abby','amount':'400'},
{'item':'111,222,333','name':'chris','amount':'500'}
]
new_lst = [
ud
for d in lst
for ud in unpack_dict(d, "item", lambda item: item.split(","))
]
gives new_lst =
[
{'amount': '400', 'item': '321', 'name': 'abby'},
{'amount': '400', 'item': '121', 'name': 'abby'},
{'amount': '400', 'item': '343', 'name': 'abby'},
{'amount': '500', 'item': '111', 'name': 'chris'},
{'amount': '500', 'item': '222', 'name': 'chris'},
{'amount': '500', 'item': '333', 'name': 'chris'}
]
Here is a working script:
lst = [{'item':'321,121,343','name':'abby','amount':'400'}, {'item':'321,121,343','name':'chris','amount':'500'}]
new_list = [{'item':j, 'name': i['name'], 'amount': i['amount']} for i in lst for j in i['item'].split(',')]
>>> print new_list
[{item:'321','name':'abby','amount':'400'},{item:'121','name':'abby','amount':'400'},{item:'343','name':'abby','amount':'400'},{item:'111','name':'chris','amount':'500'},{item:'222','name':'chris','amount':'500'},{item:'333','name':'chris','amount':'500'}]
Demo: http://repl.it/RaE