How to conditionally select elements in a list comprehension? - python

I couldn't find any examples that match my use case. Still working through my way in python lists and dictionaries.
Problem:
all_cars = {'total_count': 3,'cars': [{'name': 'audi','model': 'S7'}, {'name': 'honda', 'model': 'accord'},{'name': 'jeep', 'model': 'wrangler'} ]}
owners = {'users':[{'owner': 'Nick', 'car': 'audi'},{'owner': 'Jim', 'car': 'ford'},{'owner': 'Mike', 'car': 'mercedes'} ]}
def duplicate():
for c in all_cars['cars']:
if c['name'] == [c['users']for c in owners['users']]:
pass
else:
res = print(c['name'])
return res
output = ['honda', 'jeep', audi']
and
def duplicate():
for c in all_cars['cars']:
if c['name'] == 'audi':
pass
else:
res = print(c['name'])
return res
output - ['honda', 'jeep']
I am trying to find matching values in both dictionaries, using list comprehension, then return non-matching values only.
Solution: Using 'in' rather than '==' operator, I was able to compare values between both lists and skip duplicates.
def duplicate():
for c in all_cars['cars']:
if c['name'] in [c['users']for c in owners['users']]:
pass
else:
res = print(c['name'])
return res

To answer the question in your title, you can conditionally add elements during a list comprehension using the syntax [x for y in z if y == a], where y == a is any condition you need - if the condition evaluates to True, then the element y will be added to the list, otherwise it will not.

I would just keep a dictionary of all of the owner data together:
ownerData = { "Shaft" : {
"carMake" : "Audi",
"carModel" : "A8",
"year" : "2015" },
"JamesBond" : {
"carMake" : "Aston",
"carModel" : "DB8",
"year" : "2012" },
"JeffBezos" : {
"carMake" : "Honda",
"carModel" : "Accord"
"year" : "1989"}
}
Now you can loop through and query it something like this:
for o in ownerData:
if "Audi" in o["carMake"]:
print("Owner %s drives a %s %s %s" % (o, o["year"], o["carMake"], o["carModel"]))
Should output:
"Owner Shaft drives a 2015 Audi A8"
This way you can expand your data set for owners without creating multiple lists.

OK, based on your feedback on the solution above, here is how I would tackle your problem. Drop your common items into lists and then use "set" to print out the diff.
all_cars = {'total_count': 3,'cars': [{'name': 'audi','model': 'S7'},
{'name': 'honda', 'model': 'accord'},{'name': 'jeep', 'model': 'wrangler'} ]}
owners = {'users':[{'owner': 'Nick', 'car': 'audi'},{'owner': 'Jim',
'car': 'ford'},{'owner': 'Mike', 'car': 'mercedes'} ]}
allCarList = []
ownerCarList = []
for auto in all_cars['cars']:
thisCar = auto['name']
if thisCar not in allCarList:
allCarList.append(thisCar)
for o in owners['users']:
thisCar = o['car']
if thisCar not in ownerCarList:
ownerCarList.append(thisCar)
diff = list(set(allCarList) - set(ownerCarList))
print(diff)
I put this in and ran it and came up with this output:
['jeep', 'honda']
Hope that helps!

Related

Writing nested loop as list comprehension

I have the following for loop I need to make Pythonic by using a list comprehension:
accounts_list = []
for a in Accounts:
rows = {
'Account': a["FullyQualifiedName"],
'Classification': a["Classification"],
'AccountType': a['AccountType']
}
accounts_list.append(rows)
accounts_df = pd.DataFrame(accounts_list)
Here is how:
accounts_list = [{'Account': a["FullyQualifiedName"],
'Classification': a["Classification"],
'AccountType': a['AccountType']} for a in Accounts]
accounts_df = pd.DataFrame(accounts_list)
Explanation:
This is a basic list comprehension:
[a for a in Accounts]
where the returned value of [a for a in Accounts] is the same as Accounts, if rows is of type list.
Add the dictionary for each iteration, and get
accounts_list = [{'Account': a["FullyQualifiedName"],
'Classification': a["Classification"],
'AccountType': a['AccountType']} for a in Accounts]
You could prepare a key mapping list and use it to build your target list items:
keyMap = [ ['Account','FullyQualifiedName'],
['Classification']*2, ['AccountType']*2 ]
accounts_list = [ {k:a[v] for k,v in keyMap} for a in Accounts ]

Combining objects in one list

I have a list of dicts that looks like this:
{
"Player_Name":"Byeong-Hun An",
"Tournament":[
{
"Name":"Arnold Palmer Invitational presented by Mastercard",
"Points":"32.80",
"Salary":"10300.00"
}
]
},
{
"Player_Name":"Byeong-Hun An",
"Tournament":[
{
"Name":"Different",
"Points":"18.80",
"Salary":"10400.00"
}
]
}
and I want this:
[
{
"Player_Name":"Byeong-Hun An",
"Tournament":[
{
"Name":"Arnold Palmer Invitational presented by Mastercard",
"Points":"32.80",
"Salary":"10300.00"
},
{
"Name":"Different",
"Points":"18.80",
"Salary":"10400.00"
}
]
}
]
I've tried collections, but it doesn't do exactly what I'm wanting. I essentially want to take every single player and combine all the tournament objects into one so each player has one object instead of each event having its own object.
Here's my code
import json
import numpy as np
import pandas as pd
from collections import Counter
# using json open the player objects file and set it equal to data
with open('PGA_Player_Objects.json') as json_file:
data = json.load(json_file)
points = []
players = []
for a in data:
for b in a['Tournament']:
points.append(int(float(b['Points'])))
for x in data:
players.append(x['Player_Name'])
def Average(lst):
unrounded = sum(lst) / len(lst)
return round(unrounded,2)
result = Counter()
for d in data:
for b in d['Tournament']:
result[d['Player_Name']] += int(float(b['Points']))
How can I do that?
if your list is in l:
l = [{'Player_Name': 'Byeong-Hun An', 'Tournament': [{'Name': 'Arnold Palmer Invitational presented by Mastercard', 'Points': '32.80', 'Salary': '10300.00'}]},
{'Player_Name': 'Byeong-Hun An', 'Tournament': [{'Name': 'Different', 'Points': '18.80', 'Salary': '10400.00'}]},]
Try this:
from itertools import groupby
result = []
for k,g in groupby(sorted(l, key=lambda x:x['Player_Name']), lambda x:x['Player_Name']):
result.append({'Player_Name':k, 'Tournament':[i['Tournament'][0] for i in g]})
Then the result will be:
[{'Player_Name': 'Byeong-Hun An',
'Tournament': [
{'Name': 'Arnold Palmer Invitational presented by Mastercard',
'Points': '32.80',
'Salary': '10300.00'},
{'Name': 'Different',
'Points': '18.80',
'Salary': '10400.00'}]}]
This works as well, and it's a more general solution that works for arbitrary key names:
from collections import defaultdict
d = defaultdict(list)
for dic in lst:
for k, v in dic.items():
if isinstance(v, list):
d[k].extend(v)
else:
d[k] = v
answer = [dict(d)]
Here's my take on a solution.
Create a new list of dictionaries
Iterate through the original list of dictionaries.
Store one copy of the beginning data for each player that is the same into the new list of dictionaries
Append additional Tournament data for each player into that one dictionary into a unified Tournament list.
Untested code below as an example, but should work with some tweaks.
listofDicts = [{'Player_Name': 'Byeong-Hun An', 'Tournament': [{'Name': 'Arnold Palmer Invitational presented by Mastercard', 'Points': '32.80', 'Salary': '10300.00'}]},{'Player_Name': 'Byeong-Hun An', 'Tournament': [{'Name': 'Different', 'Points': '18.80', 'Salary': '10400.00'}]}]
newListOfDicts = []
playerName = " "
playerNo = -1
for dicts in listofDicts:
if playerName == dicts['Player_Name']:
newListOfDicts[playerNo]['Tournament'].append(dicts['Tournament'][0])
else:
newListOfDicts.append(dicts)
playerName = dicts['Player_Name']
playerNo += 1

how to convert nested list which contain key - value pair to json format using python

I have ['key','value'] format list, which also contain sub-list. How can I convert nested list to JSON format in python
[[' key ', ' 1542633482511430199'
],
['value=>>>BasicData',
[['isConfirmAndOrder', '0'],['brmRequestId', 'BR-2018-0000124'],
['requestType','batch'],['projectId', 'PRJ-2018-0000477'],
['createdOn', 'Mon Nov 19 18:48:02 IST 2018']]
],
['createdBy=>>>BasicData',
[['userId', '999996279'], ['email', 'ITEST275#ITS.JNJ.com'],
['firstName', 'Iris'], ['lastName', 'TEST275'],
['ntId', 'itest275'], ['region', 'NA'],
[' LastAccessTime ', ' 1542639905785 ']]
]
]
Excepted format is
{
"key": "1542633482511430199",
"value=>>>BasicData": {
"isConfirmAndOrder": "0",
"brmRequestId": "BR-2018-0000124"
.
},
"createdBy=>>>BasicData": {
"userId": "999996279",
"email": "ITEST275#ITS.JNJ.com"
.
}
.
}
Actually format of large data is:
[
[
['key11','value11']
['key12',['key13','value13']]
['key14',['key15','value15']]
]
[
['key21','value21']
['key22',['key23','value23']]
['key24',['key25','value25']]
]
]
You can write a simple recursive function for this:
def to_dict_recursive(x):
d = {}
for key, value in x:
if isinstance(value, list):
value = to_dict_recursive(value)
else:
value = value.strip() # get rid of unnecessary whitespace
d[key.strip()] = value
return d
to_dict_recursive(x)
# {'createdBy=>>>BasicData': {'displayName': 'Iris TEST275',
# 'email': 'ITEST275#ITS.JNJ.com',
# 'firstName': 'Iris',
# 'lastName': 'TEST275',
# 'ntId': 'itest275',
# 'region': 'NA',
# 'roles': '[0]CG510_DHF_AP_Role',
# 'userId': '999996279'},
# 'formulaDetails=>>>BasicData': {'CreationTime': '1542633482512',
# 'LastAccessTime': '1542639905785',
# 'batchSizeUnits': 'kg<<<<<<',
# 'hitCount': '1',
# 'version': '1'},
# 'key': '1542633482511430199',
# 'value=>>>BasicData': {'brmRequestId': 'BR-2018-0000124',
# 'createdMonth': 'Nov',
# 'createdOn': 'Mon Nov 19 18:48:02 IST 2018',
# 'department': 'Global Packaging',
# 'gxp': '1',
# 'id': '1542633482511430199',
# 'isConfirmAndOrder': '0',
# 'isFilling': 'false',
# 'projectId': 'PRJ-2018-0000477',
# 'projectName': 'Automation_Product_By_Admin',
# 'requestType': 'batch',
# 'status': 'New',
# 'statusDescription': 'Batch request created',
# 'updatedOn': 'Mon Nov 19 18:48:02 IST 2018'}}
(I ran this in Python 3.6 so the order of the keys in the dictionary representation is different than insertion order. In Python 3.7+ this would be different.)
You can even make this into a dict comprehension:
def to_dict_recursive(x):
return {key.strip(): to_dict_recursive(value) if isinstance(value, list)
else value.strip
for key, value in x}
Since apparently some elements in your object are not a two-element list of key and value, you can add a simple guard against that:
def to_dict_recursive(x):
d = {}
try:
for key, value in x:
if isinstance(value, list):
value = to_dict_recursive(value)
else:
value = value.strip()
d[key.strip()] = value
except ValueError:
return x
return d
x = [[' key ', ' 1542633482511430199'],
["test", ["a", "b", "c"]]
]
to_dict_recursive(x)
# {'key': '1542633482511430199', 'test': ['a', 'b', 'c']}
Note that if mylist is a key-value pair list, then dict(mylist) simply returns a dictionary version of it. The tricky part is traversing deep into those nested lists to replace them with dictionaries. Here's a recursive function that does that:
# Where <kv> is your giant list-of-lists.
def kv_to_dict(kv):
if isinstance(kv, list):
kv = dict(kv)
for k in kv:
if isinstance(kv[k], list):
kv[k] = kv_to_dict(kv[k])
return kv
newdict = kv_to_dict(kvpairs)
Once you have things converted to a dictionary, you can just use json.dumps() to format it as JSON:
import json
as_json = json.dumps(newdict, indent=4)
print(as_json)
I see though that you've tried something similar and got an error. Are you sure that all of the lists in your data are really key-value pairs, and not for example a list of 3 strings?

How to filter multiple JSON data with Python?

I'm having some hard time filtering multiple json datas, I need to know the type of each data and if the type corresponds to a fruit then print the element's fields key, see python example comments for a better explanation.
Here's what the JSON looks like :
#json.items()
{
'type': 'apple',
'fields': {
'protein': '18g',
'glucide': '3%',
}
},
{
'type': 'banana',
'fields': {
'protein': '22g',
'glucide': '8%',
}
},
Here's what I tried to do :
for key, value in json.items(): #access json dict.
if key == 'type': #access 'type' key
if value == 'apple': #check the fruit
if key == 'fields': #ERROR !!! Now I need to access the 'fields' key datas of this same fruit. !!!
print('What a good fruit, be careful on quantity!')
print('more :' + value['protein'] + ', ' + value['glucid'])
if value == 'banana': #if not apple check for bananas
print('One banana each two days keeps you healthy !')
print('more:' + value['protein'] + ', ' + value['glucid'])
Is there a way I can achieve this ?
What you have seems to be a list of dicts.
You then check if keys type and fields exist in the dictionary before checking their value, like this:
for d in data: # d is a dict
if 'type' in d and 'fields' in d:
if d['type'] == 'apple':
... # some print statements
elif d['type'] == 'banana':
... # some more print statements
Based on your representation of the JSON, it appears that is actually a list, not a dictionary. So in order to iterate through it, you could try something like this:
for item in json:
fields = item['fields']
if item['type'] == 'banana':
print('Bananas have {} of protein and {} glucide'.format(fields['protein'], fields['glucide']))
elif item['type'] == 'apple':
print('Apples have {} of protein and {} glucide'.format(fields['protein'], fields['glucide']))

How can I change the value of a node in a python dictionary by following a list of keys?

I have a bit of a complex question that I can't seem to get to the bottom of. I have a list of keys corresponding to a position in a Python dictionary. I would like to be able to dynamically change the value at the position (found by the keys in the list).
For example:
listOfKeys = ['car', 'ford', 'mustang']
I also have a dictionary:
DictOfVehiclePrices = {'car':
{'ford':
{'mustang': 'expensive',
'other': 'cheap'},
'toyota':
{'big': 'moderate',
'small': 'cheap'}
},
'truck':
{'big': 'expensive',
'small': 'moderate'}
}
Via my list, how could I dynamically change the value of DictOfVehiclePrices['car']['ford']['mustang']?
In my actual problem, I need to follow the list of keys through the dictionary and change the value at the end position. How can this be done dynamically (with loops, etc.)?
Thank you for your help! :)
Use reduce and operator.getitem:
>>> from operator import getitem
>>> lis = ['car', 'ford', 'mustang']
Update value:
>>> reduce(getitem, lis[:-1], DictOfVehiclePrices)[lis[-1]] = 'cheap'
Fetch value:
>>> reduce(getitem, lis, DictOfVehiclePrices)
'cheap'
Note that in Python 3 reduce has been moved to functools module.
A very simple approach would be:
DictOfVehiclePrices[listOfKeys[0]][listOfKeys[1]][listOfKeys[2]] = 'new value'
print reduce(lambda x, y: x[y], listOfKeys, dictOfVehiclePrices)
Output
expensive
In order to change the values,
result = dictOfVehiclePrices
for key in listOfKeys[:-1]:
result = result[key]
result[listOfKeys[-1]] = "cheap"
print dictOfVehiclePrices
Output
{'car': {'toyota': {'small': 'cheap', 'big': 'moderate'},
'ford': {'mustang': 'cheap', 'other': 'cheap'}},
'truck': {'small': 'moderate', 'big': 'expensive'}}
You have a great solution here by #Joel Cornett.
based on Joel method you can use it like this:
def set_value(dict_nested, address_list):
cur = dict_nested
for path_item in address_list[:-2]:
try:
cur = cur[path_item]
except KeyError:
cur = cur[path_item] = {}
cur[address_list[-2]] = address_list[-1]
DictOfVehiclePrices = {'car':
{'ford':
{'mustang': 'expensive',
'other': 'cheap'},
'toyota':
{'big': 'moderate',
'small': 'cheap'}
},
'truck':
{'big': 'expensive',
'small': 'moderate'}
}
set_value(DictOfVehiclePrices,['car', 'ford', 'mustang', 'a'])
print DictOfVehiclePrices
STDOUT:
{'car': {'toyota': {'small': 'cheap', 'big': 'moderate'}, 'ford':
{'mustang': 'a', 'other': 'cheap'}}, 'truck': {'small': 'moderate',
'big': 'expensive'}}
def update_dict(parent, data, value):
'''
To update the value in the data if the data
is a nested dictionary
:param parent: list of parents
:param data: data dict in which value to be updated
:param value: Value to be updated in data dict
:return:
'''
if parent:
if isinstance(data[parent[0]], dict):
update_dict(parent[1:], data[parent[0]], value)
else:
data[parent[0]] = value
parent = ["test", "address", "area", "street", "locality", "country"]
data = {
"first_name": "ttcLoReSaa",
"test": {
"address": {
"area": {
"street": {
"locality": {
"country": "india"
}
}
}
}
}
}
update_dict(parent, data, "IN")
Here is a recursive function to update a nested dict based on a list of keys:
1.Trigger the update dict function with the required params
2.The function will iterate the list of keys, and retrieves the value from the dict.
3.If the retrieved value is dict, it pops the key from the list and also it updates the dict with the value of the key.
4.Sends the updated dict and list of keys to the same function recursively.
5.When the list gets empty, it means that we have reached the desired the key, where we need to apply our replacement. So if the list is empty, the funtion replaces the dict[key] with the value

Categories

Resources