Delete entry from a dictionary of dictionaries - python

I have a dictionary of dictionaries..
self.books = {}
newbook = {'Quantity': '1', 'Price': '1.58', 'Id': '1006', 'Title': 'Book1', 'Status': 'Out'}
I add orders like so:
self.books[newbook['Price']] = newbook
To show all the book entries:
for books in self.books.values():
print("{0}".format(order))
{'Quantity': '3', 'Price': '7.56', 'Id': '1003', 'Title': 'To kill a mock', 'Status':'In'}
{'Quantity': '7', 'Price': '2.9', 'Id': '1002', 'Title': 'LOTR', 'Status':'In'}
{'Quantity': '2', 'Price': '5.45', 'Id': '1001', 'Title': 'HPATFS', 'Status':'Out'}
{'Quantity': '12', 'Price': '11.57', 'Id': '1004', 'Title': 'Best book ever', 'Status':'Out'}
Unfortunately I can't delete a book entry based on Id or Price or Status? I've tried del or pop, but the entry still remains.
for k, v in self.books.items():
if k == books['Id']:
# del self.books[k]
self.books.pop(books['Id'], None)

First and foremost, you can't use values that you are not sure are unique as keys for a dictionary. Dictionaries are indexed by their key and indexing has to be unique. In fact, the language doesn't even allow you to try to add two entries with the same value. Adding the second item simply overwrites the first:
>>> d = {'a':1}
>>> d.update({'a':2})
>>> print(d)
{'a': 2}
So, you definitely should use the 'Id' value as the key for your dictionary, assuming your Ids are in fact unique.
Because of this, the rest of your question boils down to finding a dictionary entry by it's value instead of it's key. For this, you have to define a behavior for when the dict contains multiple entries with that value. I'm going to assume you want a list of all Ids with the specified pricetag.
The only way I can think of for this that accounts for the possibility of multiple entries with the same value is simply iterating over dict:
def findKeysByValue(dic, value):
match_keys = []
for key, val in dic.items():
if val == value:
match_keys.append(key)
return match_keys
(use dic.iteritems() instead for Python 2.X)
Which yields for example:
>>> d = {'k1':1,'k2':2,'k3':3, 'k4':2, 'k5':2}
>>> findKeysByValue(d,2)
['k5', 'k2', 'k4']
Once you know the key of the book that interests you, you can apply all dictionary operations on that key.
There are two different problems with the last part of your code. Firstly, pop takes a key from your dictionary as an argument, not a value. Also, this code produces a RuntimeError: dictionary changed size during iteration, because you iterate over the dictionary itself and remove an item every cycle. You can circumvent this by iterating over a copy of your dict, i.e.:
copy_dict = self.books.copy()
for k in copy_dict:
if k == books['Id']:
self.books.pop(k, None)
Depending on the size of self.books though, this may not be suitable, because you have double the space requirement.

Related

Rename duplicates in list of dictionaries by appending progressive numbers at end

Given a list of dictionaries like this
a_list = [{'name':'jennifer','roll_no':22}, {'name':'kristina','roll_no':26},
{'name':'jennifer','roll_no':18}, {'name':'kristina','roll_no':33}]
How could this be renamed to
a_list = [{'name':'jennifer','roll_no':22}, {'name':'kristina','roll_no':26},
{'name':'jennifer 1','roll_no':18}, {'name':'kristina 1','roll_no':33}]
You want to construct a new list of dictionaries, but whenever a new dictionary is added that has a 'name' value that was already present, you want to use the next available option.
There's different approaches but one would be:
loop over all the dictionaries in a_list and add them to a new list
before adding them, check some register of used names to see if their name is in there, if not, just add it; if so, get and increase the number associated with it and update the dictionary
So, in code:
a_list = [
{'name':'jennifer','roll_no':22}, {'name':'kristina','roll_no':26},
{'name':'jennifer','roll_no':18}, {'name':'kristina','roll_no':33}
]
names = {}
result = []
for d in a_list:
if (name := d['name']) not in names:
names[name] = 0
else:
names[name] += 1
d['name'] = f'{name} {names[name]}'
result.append(d)
print(result)
Result:
[{'name': 'jennifer', 'roll_no': 22}, {'name': 'kristina', 'roll_no': 26}, {'name': 'jennifer 1', 'roll_no': 18}, {'name': 'kristina 1', 'roll_no': 33}]

How to merge multiple dictionaries into one when iterating over them one by one in python

I have list of dictionaries and I am trying to take each dictionary and group them into one dictionary after iterations. Is there a simple way of doing this. So far I am taking each dictionary after each iteration and appending them into a list. After the iteration I get an output like below:
data = [{'disabled': False, 'id': '28394', 'self': 'www.google.com/28394', 'value': 'Tuesday'}, {'disabled': False, 'id': '23433', 'self': 'www.google.com/23433', 'value': 'Wednsday'}]
I would like to either convert it from a list to a single dictionary or somehow merge each dictionary into one like below.
data = {'disabled': False, 'id': '28394', 'self': 'www.google.com/28394', 'value': 'Tuesday', 'disabled': False, 'id': '23433', 'self': 'www.google.com/23433', 'value': 'Wednsday'}
Once I get that I want to add the dictionary using the dict() method that creates the empty dictionary to store those values.
Below is my code:
elif(key == 'customfield_12951'):
newDictionaryValues = []
for issueItemInspection in oIssues['customfield']:
if(oIssues[key] == None):
values = {'value': None}
verificationDictNone = dict(values)
iterateDictIssues(verificationDictNone, listInner)
else:
if(len(oIssues[key]) == 1):
values = issueItemInspection
verificationDict = dict(values)
iterateDictIssues(verificationDict, listInner)
else:
values = issueItemInspection
newDictionaryValues.append(values)
print(newDictionaryValues)
verificationDictValues = dict(values)
iterateDictIssues(verificationDictValues, listInner)
There are multiple keys holding each dictionary and as you can see the issueItemInspection is carrying each individual dictionary. As each key dictionary gets appended I would like to merge these all into one or convert it from a list to a single dictionary. Right now it is a big list of dictionaries.
I don't fully understand your point, but how about storing values with same keys into list?
from collections import defaultdict
data = [{'disabled': False, 'id': '28394', 'self': 'www.google.com/28394', 'value': 'Tuesday'}, {'disabled': False, 'id': '23433', 'self': 'www.google.com/23433', 'value': 'Wednsday'}]
d = defaultdict(list)
for dictionary in data:
for k, v in dictionary.items():
d[k].append(v)
print(d)
You can't get to the requested data since your dictionnary have multiple key definition, it will only keep the last key value:
>>> dict_test = {'test': 1, 'test': 2}
>>> print(dict_test )
{'test': 2}

Fetch value from python dictionary and pass one by one

I have dictionary as mentioned below.
a={'name':['test1','test2'],'regno':['123','345'],'subject':
['maths','science'],'standard':['3','4']}
I need verify below things.
Each values count dictionary should be match.
Fetch the values from each keys one by one and pass it to my other function one by one.
name = 'test1' regno = '123' subject='maths' standard='3'
name = 'test2' regno = '345' subject='science' standard='4'
I have tried using below code but i am stuck here to find out exact way.
a={'name':['test1','test2'],'regno':['123','345'],'subject':['maths','science'],'standard':['3','4']}
lengths = [len(v) for v in a.values()]
if (len(set(lengths)) <= 1) == True:
print('All values are same')`
else:
print('All values are not same')
Need your help to fetch values one by one from each keys and pass it to a function.
Try looping over your dictionary items and then over the lists in values:
for key, vals_list in a.items():
if len(set(vals_list)) <= 1:
print(f'{key}: All values are same!')
# Will do nothing if `vals_list` is empty
for value in vals_list:
your_other_func(value)
You can get it done this way:
a={'name':['test1','test2'],'regno':['123','345'],'subject':
['maths','science'],'standard':['3','4']}
w = [{'name':a['name'][i], 'regno':a['regno'][i], 'standard':a['standard'][i]} for i
in range(len(a['name']))]
for x in range(len(w)):
#your_func(w[x]['name'], w[x]['reno'], w[x]['standard'])
print(w[x]['name'], w[x]['regno'], w[x]['standard'])
I would rebuild a into a list of dictionaries, and then use dict-unpacking to dynamically give the dictionary to the function instead:
def func(name, regno, subject, standard):
print("name={}, regno={}, subject={}, standard={}".format(name, regno, subject, standard))
a={'name':['test1','test2'],'regno':['123','345',],'subject':
['maths','science'],'standard':['3','4']}
new_a = [dict(zip(a.keys(), x)) for x in list(zip(*a.values()))]
print(new_a)
for d in new_a:
func(**d)
Output:
[{'name': 'test1', 'regno': '123', 'subject': 'maths', 'standard': '3'}, {'name': 'test2', 'regno': '345', 'subject': 'science', 'standard': '4'}]
name='test1', regno='123', subject='maths', standard='3'
name='test2', regno='345', subject='science', standard='4'

Iterate though a list of Dict Values and remove elements from that list

I have a list of dictionaries like below:
Dict1 = [{'Title': 'Title1', 'Attributes':['name1.50', 'name2.40', 'name1.90']},
{'Title': 'Title2', 'Attributes':['name2.90', 'name1.40', 'name1.90']}]
I want to iterate through this dictionary and then iterate the 'Attributes' key in each dictionary to look for values starting with 'name1' and not having .90 in it, and remove it from the 'Attributes' key.
So the final dictionary should look like:
Dict1 = [{'Title': 'Title1', 'Attributes':['name1.90']},
{'Title': 'Title2', 'Attributes':['name2.90', 'name1.90']}]
I have the iteration logic as
for item in Dict1:
for name in item['Attributes']:
if 'name1' in name:
if name.split(".")[1] not '90':
item['Attributes'].remove(name)
However I see that it doesn't remove all the values that are missing .90 in it. I tried some list comprehensions but did not help. I am new to python and coding in general, so I'm sure there is a much easier way to do this.
name.split(".")[1] not '90' is a syntax error, just use !=. Python is not only a cryptic language made of not, is, reduce, lambda...
item['Attributes'].remove(name) is done when you're iterating on the elements. That's bug prone: you can skip some elements
Best way is to rebuild your list of dictionaries in a list comprehension, and a dict comprehension with a filter for each dict:
Dict1 = [{'Title': 'Title1', 'Attributes':['name1.50', 'name2.40', 'name1.90']}, {'Title': 'Title2', 'Attributes':['name2.90', 'name1.40', 'name1.90']}]
new_dict_list = [{'Title':d['Title'], 'Attributes':[v for v in d['Attributes'] if v.endswith(".90")]} for d in Dict1]
result:
[{'Attributes': ['name1.90'], 'Title': 'Title1'},
{'Attributes': ['name2.90', 'name1.90'], 'Title': 'Title2'}]
with one less comprehension:
new_dict_list = []
for d in Dict1:
values = [v for v in d['Attributes'] if v.endswith(".90")]
new_dict_list.append({'Title':d['Title'], 'Attributes':values})
v.endswith(".90") could be 90 in v or not v.startswith('name1') and v.endswith('.90'), not sure of the exact condition, but I'll let that to the reader.
you were very close to the right answer. In Python you can't manipulate values in a key/value pair. So instead, I tried this approach and this would produce your wanted output.
for x in Dict1:
new_attributes = []
print(x)
for i in x['Attributes']:
if i.split('.')[1] == '90':
new_attributes.append(i)
del x['Attributes'] #Not required. Can directly write the new list in the key
x['Attributes'] = new_attributes
This creates a new list storing only the values you want, deletes the old Attributes key and creates a new one with the new list.
def solve():
array = [{'Title': 'Title1', 'Attributes':['name1.50', 'name2.40', 'name1.90']}, {'Title': 'Title2', 'Attributes':['name2.90', 'name1.40', 'name1.90']}]
for item in array:
new_names = []
for name in item['Attributes']:
if '90' in name: new_names.append(name)
elif 'name1' not in name: new_names.append(name)
item['Attributes'] = new_names
print(array)
solve()
Output: [{'Title': 'Title1', 'Attributes': ['name2.40', 'name1.90']}, {'Title': 'Title2', 'Attributes': ['name2.90', 'name1.90']}]

Merge dictionaries in different lists in Python

I need to merge two lists with dictionaries in them:
dict1 = [{'Count': '307', 'name': 'Other', 'Percentage': '7.7%'}, {'Count': '7,813', 'name': 'Other', 'Percentage': '6.8%'}...]
dict2 = [{'Place': 'Home'}, {'Place':'Forest'},...]
There are 56 elements in the first list (56 dictionaries) and 14 elements in the second list (dict2). What I want to do is inset first element from dict2 to first four elements of dict 1 and repeat the process until all 56 elements in dict1 have {Place:x}.
So eventually what I want to get is:
newdict = [{'Count': '307', 'name': 'Other', 'Percentage': '7.7%', 'Place': 'Home'}, {'Count': '7,813', 'name': 'Other', 'Percentage': '6.8%', 'Place':'Home'},{'Name': 'Other', 'Percentage': '6.6%', 'Place': 'Home', 'Count': '1,960'},{'Name': 'Other', 'Percentage': '7.6%', 'Place': 'Home', 'Count': '1,090'},{'Name': 'Other', 'Percentage': '7.6%', 'Place': 'Forest', 'Count': '1,090'} ]
and so on..
When dict2 is exhausted, it should start from first element again.
So I updated question. My first take on this problem was to increase number of same key:values in dict2 to:
dict2 = [{'Place': 'Home'}, {'Place':'Home'},{'Place':'Home'},{'Place':'Home'},{'Place':'Forest'},{'Place':'Forest'}...]
and then use the same method mentioned below to merge dictionaries. But I believe there should be a way to do this without changing dict2.
We'll use zip and itertools.cycle to pair up elements from the two lists.
from itertools import cycle
for a, b in zip(dict1, cycle(dict2)):
a.update(b)
If you don't want to modify the original list, it's a little more complex.
from itertools import cycle, chain
new_list = [{k:v for k, v in chain(a.items(), b.items())} for a, b in zip(dict1, cycle(dict2))]
You can use zip():
res = []
for i, j in zip(dict1, dict2):
res.append(i)
res[-1].update(j)
If the number of items in your dicts are not the same, you can use itertools.izip_longest() with fillvalue param set to {}:
res = []
for i, j in itertools.izip_longest(dict1, dict2, fillvalue={}):
res.append(i)
res[-1].update(j)
Using modulo:
new_list = []
x = len(dict2)
for v, item in enumerate(dict1):
z = item.copy()
z['Place'] = dict2[v % x]['Place']
new_list.append(z)
How about simply creating an empty dictionary called result and simply updating it with the list of existing dictionaries you want merged, for example:
def merge_dicts(*dict_args):
"""
Given any number of dicts, shallow copy and merge into a new dict,
precedence goes to key value pairs in latter dicts.
:param dict_args: a list of dictionaries
:return: dict - the merged dictionary
"""
result = {}
for dictionary in dict_args:
result.update(dictionary)
return result

Categories

Resources