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
Related
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.
Say I have two dictionaries:
dict_one = {abc: 5, bat: 1, car: 6, xray: 3}
dict_two = {abc: 2, jfk: 4, zit: 7}
I want to compare the keys of both and create a new dictionary which contains only the keys of dict_one which don't occur in dict_two.
The new dictionary would look like this:
unique_dict = {bat: 1, car: 6, xray: 3}
This is what I am trying at the moment (the first part found here: Python read two dictionaries compare values and create third dictionary)
However I know the problem is that I can't update(key, value) as it takes only one argument, but I just don't know how to do this correctly.
d1_values = set(dict_one.keys())
d2_values = set(dict_two.keys())
words_in_both = d1_values & d2_values
not_in_both = d1_values ^ d2_values
unique_dict = {}
for key, value in dict_one.items():
for word in words_in_both:
if key != word:
unique_dict.update(key, value) # this is not correct
You could use the following dictionary comprehension to keep the key/value pairs in dict_one if they are not in dict_two:
{k:v for k,v in dict_one.items() if k not in dict_two}
# {'bat': 1, 'car': 6, 'xray': 3}
Sets and dict views already support subtraction to keep only the values in the left hand side not found in the right. So your code could simplify to:
{k: dict_one[k] for k in dict_one.keys() - dict_two.keys()}
yatu's answer is probably better in this specific case (no set temporary required), but I figured I'd point out set/view subtraction as well as showing no conversion to set itself is necessary (views can be used as set-like objects already).
def filter_dicts(d1, d2):
"""Return d1 items that are not in d2"""
return {title: value for title, value in d1.items() if title not in d2}
I was running this code through python tutor, and was just confused as to how the keys and values get switched around. I also was confused as to what value myDict[d[key]] would correspond to as I'm not sure what the d in [d[key]] actually does.
def dict_invert(d):
'''
d: dict
Returns an inverted dictionary according to the instructions above
'''
myDict = {}
for key in d.keys():
if d[key] in myDict:
myDict[d[key]].append(key)
else:
myDict[d[key]] = [key]
for val in myDict.values():
val.sort()
return myDict
print(dict_invert({8: 6, 2: 6, 4: 6, 6: 6}))
In your function d is the dictionary being passed in. Your code is creating a new dictionary, mapping the other direction (from the original dictionary's values to its keys). Since there may not be a one to one mapping (since values can be repeated in a dictionary), the new mapping actually goes from value to a list of keys.
When the code loops over the keys in d, it then uses d[key] to look up the corresponding value. As I commented above, this is not really the most efficient way to go about this. Instead of getting the key first and indexing to get the value, you can instead iterate over the items() of the dictionary and get key, value 2-tuples in the loop.
Here's how I'd rewrite the function, in what I think is a more clear fashion (as well as perhaps a little bit more efficient):
def dict_invert(d):
myDict = {}
for key, value in d.items(): # Get both key and value in the iteration.
if value in myDict: # That change makes these later lines more clear,
myDict[value].append(key) # as they can use value instead of d[key].
else:
myDict[value] = [key] # here too
for val in myDict.values():
val.sort()
return myDict
The function you are showing inverts a dictionary d. A dictionary is a collection of unique keys that map to values which are not necessarily unique. That means that when you swap keys and values, you may get multiple keys that have the same value. Your function handles this by adding keys in the input to a list in the inverse, instead of storing them directly as values. This avoids any possibility of conflict.
Let's look at a sample conceptually first before digging in. Let's say you have
d = {
'a': 1,
'b': 1,
'c': 2
}
When you invert that, you will have the keys 1 and 2. Key 1 will have two values: 'a' and 'b'. Key 2 will only have one value: 'c'. I used different types for the keys and values so you can tell immediately when you're looking at the input vs the output. The output should look like this:
myDict = {
1: ['a', 'b'],
2: ['c']
}
Now let's look at the code. First you initialize an empty output:
myDict = {}
Then you step through every key in the input d. Remember that these keys will become the values of the output:
for key in d.keys():
The value in d for key is d[key]. You need to check if that's a key in myDict since values become keys in the inverse:
if d[key] in myDict:
If the input's value is already a key in myDict, then it maps to a list of keys from d, and you need to append another one to the list. Specifically, d[key] represents the value in d for the key key. This value becomes a key in myDict, which is why it's being indexed like that:
myDict[d[key]].append(key)
Otherwise, create a new list with the single inverse recorded in it:
else:
myDict[d[key]] = [key]
The final step is to sort the values of the inverse. This is not necessarily a good idea. The values were keys in the input, so they are guaranteed to be hashable, but not necessarily comparable to each other:
for val in myDict.values():
val.sort()
The following should raise an error in Python 3:
dict_invert({(1, 2): 'a', 3: 'b'})
myDict[d[key]] takes value of d[key] and uses it as a key in myDict, for example
d = {'a': 'alpha', 'b': 'beta'}
D = {'alpha': 1, 'beta': 2}
D[d['a']] = 3
D[d['b']] = 4
now when contents of d and D should be as following
d = {'a': 'alpha', 'b': 'beta'}
D = {'alpha': 3, 'beta': 4}
d is the dictionary you are passing into the function
def dict_invert(d)
When you create
myDict[d[key]] = d
Its meaning is
myDict[value of d] = key of d
Resulting in
myDict = {'value of d': 'key of d'}
I want to sort a list of dictionaries based on the presence of keys. Let's say I have a list of keys [key2,key3,key1], I need to order the list in such a way the dictionary with key2 should come first, key3 should come second and with key1 last.
I saw this answer (Sort python list of dictionaries by key if key exists) but it refers to only one key
The sorting is not based on value of the 'key'. It depends on the presence of the key and that too with a predefined list of keys.
Just use sorted using a list like [key1 in dict, key2 in dict, ...] as the key to sort by. Remember to reverse the result, since True (i.e. key is in dict) is sorted after False.
>>> dicts = [{1:2, 3:4}, {3:4}, {5:6, 7:8}]
>>> keys = [5, 3, 1]
>>> sorted(dicts, key=lambda d: [k in d for k in keys], reverse=True)
[{5: 6, 7: 8}, {1: 2, 3: 4}, {3: 4}]
This is using all the keys to break ties, i.e. in above example, there are two dicts that have the key 3, but one also has the key 1, so this one is sorted second.
I'd do this with:
sorted_list = sorted(dict_list, key = lambda d: next((i for (i, k) in enumerate(key_list) if k in d), len(key_list) + 1))
That uses a generator expression to find the index in the key list of the first key that's in each dictionary, then use that value as the sort key, with dicts that contain none of the keys getting len(key_list) + 1 as their sort key so they get sorted to the end.
How about something like this
def sort_key(dict_item, sort_list):
key_idx = [sort_list.index(key) for key in dict_item.iterkeys() if key in sort_list]
if not key_idx:
return len(sort_list)
return min(key_idx)
dict_list.sort(key=lambda x: sort_key(x, sort_list))
If the a given dictionary in the list contains more than one of the keys in the sorting list, it will use the one with the lowest index. If none of the keys are present in the sorting list, the dictionary is sent to the end of the list.
Dictionaries that contain the same "best" key (i.e. lowest index) are considered equal in terms of order. If this is a problem, it wouldn't be too hard to have the sort_key function consider all the keys rather than just the best.
To do that, simply return the whole key_idx instead of min(key_idx) and instead of len(sort_list) return [len(sort_list)]
If I have dict like this:
some_dict = {'a': 1, 'b': 2, 'c': 2}
How to get keys that have values 2, like this:
some_dict.search_keys(2)
This is example. Assume some_dict is has many thousands or more keys.
You can do it like this:
[key for key, value in some_dict.items() if value == 2]
This uses a list comprehension to iterate through the pairs of (key, value) items, selecting those keys whose value equals 2.
Note that this requires a linear search through the dictionary, so it is O(n). If this performance is not acceptable, you will probably need to create and maintain another data structure that indexes your dictionary by value.
you can also use dictionary comprehension, if you want result to be dictionary
{ x:y for x,y in some_dict.items() if y == 2}
output:
{'c': 2, 'b': 2}
Well, you can use generator to produce found key values, one by one, instead of returning all of them at once.
The function search_keys returns generator
def search_keys(in_dict, query_val):
return (key for key, val in in_dict.iteritems() if val == query_val)
# get keys, one by one
for found_key in search_keys(some_dict, 2):
print(found_key)