Add items in nested dictionaries based on ID number in python - python

I have dictionaries nested in a list. The dictionaries are set up as follows:
{'ID': 123, 'Balance': 45, 'Comments': None}
I have multiple of these dictionaries in a list, so the list looks like this:
[{'ID': 123, 'Balance': 45, 'Comments': None}, {'ID': 456, 'Balance': 78, 'Comments': None}]
What I'm trying to do, is check to see if there is already a dictionary with the ID from the input in the list, and if there is, add the Balance from the input.
Is there any readable pythonic way to do this?

What I'm hearing here is "how do I get an item from a list, given that I know some unique key value about it?". How much are you committed to keeping the current data structure? I'm inclined to dispense with the list entirely and use a dict-of-dicts.
d = {
123: {'Balance': 45, 'Comments': None}
456: {'Balance': 78, 'Comments': None}
}
now checking if an id exists is just if some_id in d: and adding to the balance is d[some_id]["Balance"] += some_amount.

data = [{'ID': 123, 'Balance': 45, 'Comments': None}, {'ID': 456, 'Balance': 78, 'Comments': None}]
any( inputData == item['ID'] for item in data )
inputData = 123
True

Iterate over the list, check that whether there is match with the ID, if yes, add the value to the existing value of BALANCE of that dict. Below is the sample code:
>>> my_dict_list = [{'ID': 123, 'Balance': 45, 'Comments': None}, {'ID': 456, 'Balance': 78, 'Comments': None}]
>>>
>>> new_id = int(raw_input())
123
>>> for dict_obj in my_dict_list:
... if new_id == dict_obj['ID']:
... dict_obj['Balance'] += float(raw_input())
...
34
>>> my_dict_list
[{'Balance': 79.0, 'ID': 123, 'Comments': None}, {'Balance': 78, 'ID': 456, 'Comments': None}]
# Value updated for "ID" 123

accounts = [
{'ID': 123, 'Balance': 45, 'Comments': None},
{'ID': 456, 'Balance': 78, 'Comments': None},
]
def update_balance(account_id, amount):
account = next((a for a in accounts if a['ID'] == account_id), None)
if account:
account['Balance'] += amount
return account
account = int(input('Account ID: '))
amount = float(input('Amount: '))
update_balance(account, amount)

Related

Check if inputted key and value exists within a Python dictionary

I was tasked to create a CRUD program using Python dictionaries. I need to write code to check if the inputted key and value already exists in the dictionary, so here is the code of dictionary plus the input that prompt the user to search for ID:
products = [
{'id': 1, 'name': 'Light bulb', 'price': 100, 'stock': 16},
{'id': 2, 'name': 'Measuring tape', 'price': 200, 'stock': 34},
{'id': 3, 'name': 'Fan', 'price': 120, 'stock': 79},
{'id': 4, 'name': 'Flat shoes', 'price': 260, 'stock': 47},
{'id': 5, 'name': 'Swiss Army knife', 'price': 80, 'stock': 12},
{'id': 6, 'name': 'Guitar', 'price': 193, 'stock': 25},
{'id': 7, 'name': 'Marble', 'price': 30, 'stock': 45},
{'id': 8, 'name': 'Stapler', 'price': 220, 'stock': 78},
{'id': 9, 'name': 'Wrench and hammer', 'price': 65, 'stock': 12}
]
id_search = int(input("Enter ID product you want to search: ")
I wanted to make the if-else statement to see if the ID exists in the products dictionary, otherwise display the message that the ID is not found. I tried the following
if id_search in products:
print("Product ID found")
else:
print("Product ID not found")
But the result is always "Product ID not found".
You have a list of dicts not just a dict. You have to search through list of dicts:
found = False
for product in products:
if product.get("id") == id_search:
found = True
break
print(found)
Note that if your dicts are sorted, you probably can use binary search.
if len([[*my_dict.values()][0] for my_dict in products if [*my_dict.values()][0] == id_search]) > 0:
print("Product ID found")
else:
print("Product ID not found")

How to add list into api call last array?

I have this code the call an api and get an answer.
I need to perform a call for ever issue_id, and store the issue id with the correct response:
issues_ids = [10495]
def get_changelog(issue_id: int):
url = f'{base_url}/{issue_id}/changelog'
response = requests.request("GET",url,headers=headers,auth=auth)
return (response.json())
def parse_json(response):
keylsit = []
for item in response['values']:
key = {
'id': item['id'],
'items': item['items']
}
(keylsit.append(key))
return keylsit
mainlist = []
for i in issues_ids:
print(i)
mainlist.extend(parse_json(get_changelog(i)))
print(mainlist)
current print :
10495
[{'id': '13613', 'items': [{'field': 'Organization text', 'fieldtype': 'custom', 'fieldId': 'customfield_10039', 'from': None, 'fromString': None, 'to': None, 'toString': 'Jabil'}]}]
I need to add the 10495 with in this array as a new key
[{issue_id: 10495, 'id': '13613', 'items': [{'field': 'Organization text', 'fieldtype': 'custom', 'fieldId': 'customfield_10039', 'from': None, 'fromString': None, 'to': None, 'toString': 'Jabil'}]}]
I tried different methods such as insert, append...

Merge dictionaries in a list of dictionaries by combining the values

Help me please.
I have query set from Model.objects.value('name', 'language__name') and it give me the list of dictionary:
list = [{'id': 1, 'name': 'Adel', 'language': 'С#'},
{'id': 1, 'name': 'Adel', 'language': 'Python'},
{'id': 5, 'name': 'Dora', 'language': 'С#'},
{'id': 5, 'name': 'Dora', 'language': 'Java'},
{'id': 6, 'name': 'Dars', 'language': 'Python'}];
how can I to do a list of dictionary but to unit key and value?
I want to get like this:
list = [{'id': 1, 'name': 'Adel', 'language':['С#','Python']},
{'id': 5, 'name': 'Dora', 'language': ['С#','Java']},
{'id': 6, 'name': 'Dars', 'language': 'Python'}];
I tried this:
mapping = {}
for d in qs:
try:
entry = mapping[d['id']] # raises KeyError
entry['language__name'].append(d['language__name']) # raises AttributeError
except KeyError:
mapping[d['id']] = d
except AttributeError:
entry['language__name'] = [entry['language__name'], d['language__name']]
print(list(mapping.values()))
You can iterate over lst and create a dictionary out where the keys correspond to "id" values in the dicts in lst and the values are dicts. In each iteration, check if the value under "language" key is a list or not and append to the list if it's a list, create a list, if not. Finally, pass the values of out to a list constructor for the final outcome.
out = {}
for d in lst:
if d['id'] in out:
if isinstance(out[d['id']]['language'], list):
out[d['id']]['language'].append(d['language'])
else:
out[d['id']]['language'] = [out[d['id']]['language'], d['language']]
else:
out[d['id']] = d
out = list(out.values())
Output:
[{'id': 1, 'name': 'Adel', 'language': ['С#', 'Python']},
{'id': 5, 'name': 'Dora', 'language': ['С#', 'Java']},
{'id': 6, 'name': 'Dars', 'language': 'Python'}]

How to rename keys in a dictionary and make a dataframe of it?

I have a complex situation which I hope to solve and which might profit us all. I collected data from my API, added a pagination and inserted the complete data package in a tuple named q1 and finally I have made a dictionary named dict_1of that tuple which looks like this:
dict_1 = {100: {'ID': 100, 'DKSTGFase': None, 'DK': False, 'KM': None,
'Country: {'Name': GE', 'City': {'Name': 'Berlin'}},
'Type': {'Name': '219'}, 'DKObject': {'Name': '8555', 'Object': {'Name': 'Car'}},
'Order': {'OrderId': 101, 'CreatedOn': '2018-07-06T16:54:36.783+02:00',
'ModifiedOn': '2018-07-06T16:54:36.783+02:00',
'Name': Audi, 'Client': {‘1’ }}, 'DKComponent': {'Name': ‘John’}},
{200: {'ID': 200, 'DKSTGFase': None, 'DK': False, ' KM ': None,
'Country: {'Name': ES', 'City': {'Name': 'Madrid'}}, 'Type': {'Name': '220'},
'DKObject': {'Name': '8556', 'Object': {'Name': 'Car'}},
'Order': {'OrderId': 102, 'CreatedOn': '2018-07-06T16:54:36.783+02:00',
'ModifiedOn': '2018-07-06T16:54:36.783+02:00',
'Name': Mercedes, 'Client': {‘2’ }}, 'DKComponent': {'Name': ‘Sergio’}},
Please note that in the above dictionary I have just stated 2 records. The actual dictionary has 1400 records till it reaches ID 1500.
Now I want to 2 things:
I want to change some keys for all the records. key DK has to become DK1. Key Name in Country has to become Name1 and Name in Object has to become 'Name2'
The second thing I want is to make a dataFrame of the whole bunch of data. My expected outcome is:
This is my code:
q1 = response_2.json()
next_link = q1['#odata.nextLink']
q1 = [tuple(q1.values())]
while next_link:
new_response = requests.get(next_link, headers=headers, proxies=proxies)
new_data = new_response.json()
q1.append(tuple(new_data.values()))
next_link = new_data.get('#odata.nextLink', None)
dict_1 = {
record['ID']: record
for tup in q1
for record in tup[2]
}
#print(dict_1)
for x in dict_1.values():
x['DK1'] = x['DK']
x['Country']['Name1'] = x['Country']['Name']
x['Object']['Name2'] = x['Object']['Name']
df = pd.DataFrame(dict_1)
When i run this I receive the following Error:
Traceback (most recent call last):
File "c:\data\FF\Desktop\Python\PythongMySQL\Talky.py", line 57, in <module>
x['Country']['Name1'] = x['Country']['Name']
TypeError: 'NoneType' object is not subscriptable
working code
lists=[]
alldict=[{100: {'ID': 100, 'DKSTGFase': None, 'DK': False, 'KM': None,
'Country': {'Name': 'GE', 'City': {'Name': 'Berlin'}},
'Type': {'Name': '219'}, 'DKObject': {'Name': '8555', 'Object': {'Name': 'Car'}},
'Order': {'OrderId': 101, 'CreatedOn': '2018-07-06T16:54:36.783+02:00',
'ModifiedOn': '2018-07-06T16:54:36.783+02:00',
'Name': 'Audi', 'Client': {'1' }}, 'DKComponent': {'Name': 'John'}}}]
for eachdict in alldict:
key=list(eachdict.keys())[0]
eachdict[key]['DK1']=eachdict[key]['DK']
del eachdict[key]['DK']
eachdict[key]['Country']['Name1']=eachdict[key]['Country']['Name']
del eachdict[key]['Country']['Name']
eachdict[key]['DKObject']['Object']['Name2']=eachdict[key]['DKObject']['Object']['Name']
del eachdict[key]['DKObject']['Object']['Name']
lists.append([key, eachdict[key]['DK1'], eachdict[key]['KM'], eachdict[key]['Country']['Name1'],
eachdict[key]['Country']['City']['Name'], eachdict[key]['DKObject']['Object']['Name2'], eachdict[key]['Order']['Client']])
pd.DataFrame(lists, columns=[<columnNamesHere>])
Output:
{100: {'ID': 100,
'DKSTGFase': None,
'KM': None,
'Country': {'City': {'Name': 'Berlin'}, 'Name1': 'GE'},
'Type': {'Name': '219'},
'DKObject': {'Name': '8555', 'Object': {'Name2': 'Car'}},
'Order': {'OrderId': 101,
'CreatedOn': '2018-07-06T16:54:36.783+02:00',
'ModifiedOn': '2018-07-06T16:54:36.783+02:00',
'Name': 'Audi',
'Client': {'1'}},
'DKComponent': {'Name': 'John'},
'DK1': False}}

Extracting value for one dictionary key in Pandas based on another in the same dictionary

This is from an R guy.
I have this mess in a Pandas column: data['crew'].
array(["[{'credit_id': '54d5356ec3a3683ba0000039', 'department': 'Production', 'gender': 1, 'id': 494, 'job': 'Casting', 'name': 'Terri Taylor', 'profile_path': None}, {'credit_id': '56407fa89251417055000b58', 'department': 'Sound', 'gender': 0, 'id': 6745, 'job': 'Music Editor', 'name': 'Richard Henderson', 'profile_path': None}, {'credit_id': '5789212392514135d60025fd', 'department': 'Production', 'gender': 2, 'id': 9250, 'job': 'Executive In Charge Of Production', 'name': 'Jeffrey Stott', 'profile_path': None}, {'credit_id': '57892074c3a36835fa002886', 'department': 'Costume & Make-Up', 'gender': 0, 'id': 23783, 'job': 'Makeup Artist', 'name': 'Heather Plott', 'profile_path': None}
It goes on for quite some time. Each new dict starts with a credit_id field. One sell can hold several dicts in an array.
Assume I want the names of all Casting directors, as shown in the first entry. I need to check check the job entry in every dict and, if it's Casting, grab what's in the name field and store it in my data frame in data['crew'].
I tried several strategies, then backed off and went for something simple.
Running the following shut me down, so I can't even access a simple field. How can I get this done in Pandas.
for row in data.head().iterrows():
if row['crew'].job == 'Casting':
print(row['crew'])
EDIT: Error Message
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-138-aa6183fdf7ac> in <module>()
1 for row in data.head().iterrows():
----> 2 if row['crew'].job == 'Casting':
3 print(row['crew'])
TypeError: tuple indices must be integers or slices, not str
EDIT: Code used to get the array of dict (strings?) in the first place.
def convert_JSON(data_as_string):
try:
dict_representation = ast.literal_eval(data_as_string)
return dict_representation
except ValueError:
return []
data["crew"] = data["crew"].map(lambda x: sorted([d['name'] if d['job'] == 'Casting' else '' for d in convert_JSON(x)])).map(lambda x: ','.join(map(str, x))
To create a DataFrame from your sample data, write:
df = pd.DataFrame(data=[
{ 'credit_id': '54d5356ec3a3683ba0000039', 'department': 'Production',
'gender': 1, 'id': 494, 'job': 'Casting', 'name': 'Terri Taylor',
'profile_path': None},
{ 'credit_id': '56407fa89251417055000b58', 'department': 'Sound',
'gender': 0, 'id': 6745, 'job': 'Music Editor',
'name': 'Richard Henderson', 'profile_path': None},
{ 'credit_id': '5789212392514135d60025fd', 'department': 'Production',
'gender': 2, 'id': 9250, 'job': 'Executive In Charge Of Production',
'name': 'Jeffrey Stott', 'profile_path': None},
{ 'credit_id': '57892074c3a36835fa002886', 'department': 'Costume & Make-Up',
'gender': 0, 'id': 23783, 'job': 'Makeup Artist',
'name': 'Heather Plott', 'profile_path': None}])
Then you can get your data with a single instruction:
df[df.job == 'Casting'].name
The result is:
0 Terri Taylor
Name: name, dtype: object
The above result is Pandas Series object with names found.
In this case, 0 is the index value for the record found and
Terri Taylor is the name of (the only in your data) Casting Director.
Edit
If you want just a list (not Series), write:
df[df.job == 'Casting'].name.tolist()
The result is ['Terri Taylor'] - just a list.
I think, both my solutions should be quicker than "ordinary" loop
based on iterrows().
Checking the execution time, you may try also yet another solution:
df.query("job == 'Casting'").name.tolist()
==========
And as far as your code is concerned:
iterrows() returns each time a pair containing:
the key of the current row,
a named tuple - the content of this row.
So your loop should look something like:
for row in df.iterrows():
if row[1].job == 'Casting':
print(row[1]['name'])
You can not write row[1].name because it refers to the index value
(here we have a collision with default attributes of the named tuple).

Categories

Resources