How do I remove key values in a dictionary? - python

Python language.
I know how to remove keys in a dictionary, for example:
def remove_zeros(dict)
dict = {'B': 0, 'C': 7, 'A': 1, 'D': 0, 'E': 5}
del dict[5]
return dict
I want to know how to remove all values with zero from the dictionary and then sort the keys alphabetically. Using the example above, I'd want to get ['A', 'C', 'E'] as a result, eliminating key values B and D completely.
To sort do I just use dict.sort() ?
Is there a special function I must use?

sorted(k for (k, v) in D.iteritems() if v)

Sometimes when you code you have to take a step back and try to go for your intent, rather than trying to do one specific thing and miss the entire big picture. In python you have this feature called list/dictionary comprehension, from which you can use to filter the input to get the results you desire. So you want to filter out all values in your dictionary that are 0, it's simply this:
{k, v for k, v in d.items() if v != 0}
Now, dictionaries are hash tables, by default they are not sortable, however there is a class that can help you with this in collections. Using the OrderedDict class to facilitate the sorting, the code will end up like this:
OrderedDict(sorted(((k, v) for k, v in d.items() if v != 0)), key=lambda t: t[0])
Also, it's highly inadvisable to name your variables with the same name as a builtin type or method, such as dict.

Related

Get keys by list of values

I have a dictionary and a list of values such as:
dictionary = {'a': 1, 'b': 2, 'c': 3, 'd': 4}
liste = [2, 3]
I would like:
result = ['b', 'c']
If I have a very large dictionary, what is the most optimal way to do this?
The keys have unique values.
The idea here is to create a reverse_dict for an efficient lookup, otherwise the complexity can be O(mn), m-number of keys, n-length of liste. A value can be duplicate, so keeping a list for the keys is also important.
result = []
reverse_dict = collections.defaultdict(list)
for key, value in dictionary.items():
reverse_dict[value].append(key)
for v in liste:
result.extend(reverse_dict[v])
dictionary = {'a': 1, 'b': 2, 'c': 3, 'd': 4}
liste = [2, 3]
result = []
for key, value in dictionary.items():
if value in liste:
result.append(key)
As a list comprehension:
result = [key for key, value in dictionary.items() if value in liste]
Lookup by value is exactly what dictionaries are not meant for.
Since you said the dictionary is very large, the most efficient solution relies on how many times you're operating on it.
If it's going to be a frequent task, you may need to create a reverse dictionary. This can be done comprehensively:
rev_dict = {v: k for k, v in dictionary.items()}
Then you can lookup the dictionary the way it's designed for.
On the contrary, an isolated case does not justify creating a copy of a very large dictionary, which can be memory and time consuming. So I came up with this awful messy un-Pythonic construct, which exploits the ordered feature of Python 3.7+ dictionaries:
list(dictionary.keys())[list(dictionary.values()).index(your_value)]
Mind you, use this only if you're desperate.
Obviously, the best solution is the one everybody knows but no-one wants: hardcode a reverse dictionary before running the script.
This can also bring some issues to your attention that the above solutions are unable to avoid at runtime (not without being explicitly handled), e.g. reversing your dict may result in having duplicate keys, which is not illegal, but will result in a sadly shortened dictionary.

update values in nested dict based on key

I have a nested dictionary and I want to update the value of an item based on its key value.
For example, I have the following dictionary and I want to set the value of every occurrence of an item with key=='p' to be 1.
my_dict = {'p': 0, 'nested_dict': {'p': 0, 'a': 2}}
For a regular dictionary (non-nested) the update method provides a simple one-liner solution:
my_dict.update((x, 1) for x, y in my_dict.items() if x=='p')
I'm looking for a similar solution for the case of nested dictionary
If the max depth of the dictionary is known and constant and the 'p's always appear at the same depth this can be solved without recursion. In all other cases, a recursive approach is needed. Based on the example problem and your comments, I will assume that the second one is true. Here is a recursive solution:
def setPto1(dct):
return {k: setPto1(v) if isinstance(v, dict) else [v, 1][k=='p'] for k, v in dct.items()}
So you basically loop through the key-value pairs with a recursive dictionary comprehension. You were not far off with your approach. If there is something you do not understand about it, leave a comment.
If [v, 1][k=='p'] makes you feel uneasy, you can replace it with the more straight-forward (1 if k=='p' else v). They are the same thing.
Maybe this could get you started (you can still make it more generic, and it might have problems with repeated keys):
from functools import reduce
def decision_func(d, item, replace_on_item, replace_val):
if item == replace_on_item:
d[item] = replace_val
else:
return d[item]
my_dict = {'p': 0, 'nested_dict': {'p': 0, 'a': 2}}
reduce(lambda d, item: decision_func(d, item, 'p', ["some_other_val", 2]), ['nested_dict', 'p'], my_dict)
print(my_dict)
Output:
{'p': 0, 'nested_dict': {'p': ['some_other_val', 2], 'a': 2}}
What is done here is that you are going to run down the nesting tree by using the reduce function, and the decision_func is the one making the decision on whether to update a given entry or return the value for that key and continue looking for the next nesting level (basically a recursion prob). Note that as written above, this is not yet a bullet proof implementation.

removing key value pairs by matching values python

I am searching for periods "." in a dictionary and trying to delete the key/value pair if I find it
if "." in dict.values():
#delete key, value pair from the dictionary
I am sure this is very simple but I cannot seem to locate an explanation.
Thanks for your help.
Create a new dictionary without those unwanted values using dictionary comprehension. Here is an example of how to do it:
>>> old_dict = {'one': '.', 'two': 2, 'three':3, 'four':'.'}
>>> new_dict = {k:v for k,v in old_dict.iteritems() if not v == '.'}
>>> new_dict
{'three': 3, 'two': 2}
using iteritems instead of items avoids creating an intermediate list and improves performance.
If you don't want to copy your dictionary, (for example if the dictionary is large, or you have a reference to it elsewhere) then you should do it this way:
ks = [k for k in d if d[k]=='.']
for k in ks:
d.pop(k)
Create your list of keys to be removed ahead of time as shown above. You don't want to modify your dictionary while iterating over it.

Python: An elegant way to delete empty lists from Python dictionary

I have a dictionary as:
default = {'a': ['alpha'], 'b': ['beta','gamma'], 'g': []}
I wish to eliminate the empty values as:
default = {'a': ['alpha'], 'b': ['beta','gamma']}
I wrote a function (following an example found on the web)
def remove_empty_keys(d):
for k in d.keys():
try:
if len(d[k]) < 1:
del[k]
except:
pass
return(d)
I have the following questions:
1- I didn't find the mistake why it always returns following -
remove_empty_keys(default)
{'a': ['alpha'], 'b': ['beta'], 'g': []}
2- Is there a built-in function to eliminate/delete Null/None/empty values from Python dictionary without creating a copy of the original dictionary?
There's no builtin for this (AFAIK), but you can do it easily with a dict comprehension:
new_dict = {k:v for k,v in original_dict.items() if v}
If you're stuck with an older version of python (pre 2.7 without dict comprehensions), you can use the dict constructor:
new_dict = dict((k,v) for k,v in original_dict.items() if v)
Note that this doesn't operate in place (as per your second question). And dictionaries don't support slice assignment like lists do, so the best* you can really do to get this all done in place is:
new_dict = {k:v for k,v in original_dict.items() if v}
original_dict.clear()
original_dict.update(new_dict)
*of course the term "best" is completely subjective.
To fix your function, change del[k] to del d[k]. There is no function to delete values in place from a dictionary.
What you are doing is deleting the variable k, not changing the dictionary at all. This is why the original dictionary is always returned.
Rewritten, your function might look like:
def remove_empty_keys(d):
for k in d.keys():
if not d[k]:
del d[k]
This assumes you want to eliminate both empty list and None values, and actually removes any item with a "false" value.
You can use dict comprehension: -
>>> default = {'a': ['alpha'], 'b': ['beta','gamma'], 'g': []}
>>> {key: value for key, value in default.iteritems() if value}
{'a': ['alpha'], 'b': ['beta', 'gamma']}
dict((k, v) for k, v in default.iteritems() if v)
This filters all items which are not empty strings, empty dict/tuple/list.
One more option is the following (without creating a new dict):
for e in [k for k,v in default.iteritems() if len(v) == 0]: default.pop(e)
Michael's answer is correct.
Stepping back, you might be able to avoid creating those empty lists at all, by use of collections.defaultdict(list)
>>> import collections
>>> d = collections.defaultdict(list)
>>> d
defaultdict(<type 'list'>, {})
>>> d["hobbits"].append("Frodo")
>>> d["hobbits"].append("Sam")
>>> d
defaultdict(<type 'list'>, {'hobbits': ['Frodo', 'Sam']})
If the values are all lists, so you can use their truth's, you could use itertools.compress:
from itertools import compress
d = {'a': ['alpha'], 'b': ['beta','gamma'], 'g': []}
new_d = dict(compress(d.items(), d.values()))
print(new_d) # {'a': ['alpha'], 'b': ['beta', 'gamma']}

extracting dictionary pairs based on value

I want to copy pairs from this dictionary based on their values so they can be assigned to new variables. From my research it seems easy to do this based on keys, but in my case the values are what I'm tracking.
things = ({'alpha': 1, 'beta': 2, 'cheese': 3, 'delta': 4})
And in made-up language I can assign variables like so -
smaller_things = all values =3 in things
You can use .items() to traverse through the pairs and make changes like this:
smaller_things = {}
for k, v in things.items():
if v == 3:
smaller_things[k] = v
If you want a one liner and only need the keys back, list comprehension will do it:
smaller_things = [k for k, v in things.items() if v == 3]
>>> things = { 'a': 3, 'b': 2, 'c': 3 }
>>> [k for k, v in things.items() if v == 3]
['a', 'c']
you can just reverse the dictionary and pull from that:
keys_values = { 1:"a", 2:"b"}
values_keys = dict(zip(keys_values.values(), keys_values.keys()))
print values_keys
>>> {"a":1, "b":2}
That way you can do whatever you need to with standard dictionary syntax.
The potential drawback is if you have non-unique values in the original dictionary; items in the original with the same value will have the same key in the reversed dictionary, so you can't guarantee which of the original keys would be the new value. And potentially some values are unhashable (such as lists).
Unless you have a compulsive need to be clever, iterating over items is easier:
for key, val in my_dict.items():
if matches_condition(val):
do_something(key)
kindly this answer is as per my understanding of your question .
The dictionary is a kind of hash table , the main intension of dictionary is providing the non integer indexing to the values . The keys in dictionary are just like indexes .
for suppose consider the "array" , the elements in array are addressed by the index , and we have index for the elements not the elements for index . Just like that we have keys(non integer indexes) for values in dictionary .
And there is one implication the values in dictionary are non hashable I mean the values in dictionary are mutable and keys in dictionary are immutable ,simply values could be changed any time .
simply it is not good approach to address any thing by using values in dictionary

Categories