Reputation: 133
I have a dictionary where some of the values corressponding to keys are empty lists. I want to delete all such keys
d = {'Receipt total': [], 'Total Amount (AED)': [], 'Grand total': [], 'Net Amount': [], 'Total': ['105.00'], 'Total (AED)': [], 'Total Invoice Amount': [], 'Invoice total': ['105.00'], 'Amount Due': ['0.00']}
Expected output:
d = {'Total': ['105.00'], 'Invoice total': ['105.00'], 'Amount Due': ['0.00']}
I tried:
for key, value in d.items():
if value is None:
del d[k]
My code is not working
Upvotes: 0
Views: 1401
Reputation: 24133
You have at least three errors in your thinking.
The first is that an empty list is the same as None
.
Only None
is the same as None
.
Secondly, comparing lists, you should use ==
. Using is
to compare a list means that, even if a list has the same values in it, if it's not the actual same memory address, it won't compare equal.
Also, as you only want to know if the list is empty, you can use the fact that in Python, empty sequences are considered False
and non-empty are considered True
, so you can use a boolean conditional: if not value:
which will be True
for an empty list. If values can be something other than lists, then empty strings, zeroes, etc are all also False
, so you might want to check more carefully.
Thirdly, you shouldn't modify the size of a container like a dict
whilst iterating over it.
Either iterate over a copy of it, or create a record of things you want to modify, and then perform the modification afterwards.
The first way, iterating over a copy:
for key, value in list(d.items()):
if not value:
del d[key]
The second way, making a set of the keys to remove:
keys_to_remove = {key for key, value in d.items()
if not value}
for key in keys_to_remove:
del d[key]
Upvotes: 3
Reputation: 8298
What about:
new_d = dict((k,v) for k,v in d.items() if v)
And if you wish to overwrite d
just change new_d
to d
.
There is some risk that might gives the wrong results:
if v
when v = []
will evaluate to Falsly, same as 0
so it might remove wrong key. In my answer I didn't address that. One can refer to the following link to understand better: What is Truthy and Falsy? How is it different from True and False?
Upvotes: 0
Reputation: 27588
If the values are all lists, so you can use their truth, you could use itertools.compress
.
>>> dict(compress(d.items(), d.values()))
{'Total': ['105.00'], 'Invoice total': ['105.00'], 'Amount Due': ['0.00']}
Upvotes: 2
Reputation: 615
The dictionary d
you have is of type Dict[str, List[str]]
. It is initialised in a way that means none of the values of the keys are None
, but rather empty lists. For example:
>>> listOfNothing = []
>>> print(listOfNothing)
[]
>>> print(type(listOfNothing))
<class 'list'>
If you want to check whether the list is empty (whether the value is an empty list), I'd suggest something like this:
for key, value in d.items():
if len(value) == 0:
[do something]
However, as correctly pointed out by others, you can't change the size of the dictionary while iterating over it. This can be solved by creating a new dictionary.
Upvotes: -1
Reputation: 317
You can use dictionary comprehension like this:
d = {'Receipt total': [], 'Total Amount (AED)': [], 'Grand total': [], 'Net Amount': [], 'Total': ['105.00'], 'Total (AED)': [], 'Total Invoice Amount': [], 'Invoice total': ['105.00'], 'Amount Due': ['0.00']}
#use dictionary comprehensiion to create a new list of values where they value is not an empty list
d = {key : value for key, value in d.items() if len(value) != 0}
print(d)
Output : {'Total': ['105.00'], 'Invoice total': ['105.00'], 'Amount Due': ['0.00']}
By using a for loop to delete items of a dictionary, it will raise RuntimeError: dictionary changed size during iteration
Upvotes: 3
Reputation: 5237
You can use a dictionary comprehension instead:
d = {'Receipt total': [], 'Total Amount (AED)': [], 'Grand total': [], 'Net Amount': [], 'Total': ['105.00'], 'Total (AED)': [], 'Total Invoice Amount': [], 'Invoice total': ['105.00'], 'Amount Due': ['0.00']}
d = {k: v for k, v in d.items() if v != []}
print(d)
# d = {'Total': ['105.00'], 'Invoice total': ['105.00'], 'Amount Due': ['0.00']}
You'll probably want to explicitly check whether the value is []
. Otherwise, you may remove things that happen to evaluate to False
("falsey"), e.g. 0 values which you may not want. Of course, this point is only relevant if your dict could contain things other than lists as values.
Upvotes: 3
Reputation: 4842
You can use:
d = {'Receipt total': [], 'Total Amount (AED)': [], 'Grand total': [], 'Net Amount': [], 'Total': ['105.00'], 'Total (AED)': [], 'Total Invoice Amount': [], 'Invoice total': ['105.00'], 'Amount Due': ['0.00']}
res = {}
for key, value in d.items():
if value:
res[key] = value
res
# {'Total': ['105.00'], 'Invoice total': ['105.00'], 'Amount Due': ['0.00']}
It is not recommended to delete items from a container during a for loop, better create a new one and add you need than delete from the original what you do not need.
For example:
a = [1,2,2,3]
for item in a:
if item > 1:
a.remove(item)
a
# [1, 2]
Leaves the second 2
because once you removed the first 2
you shifted indexes and your for loop has already checked index 1
but now your second 2
is at index 1
and it gets unchecked.
Upvotes: 1