Reverse the order of elements in a dictionary - python

If I have a dictionary dict1 = {1:'a', 2:'c', 'd':'gh'}
and I want to reverse it so that dict2 = {'d':'gh', 2:'c', 1:'a'}. I do not want to change the maping of the dictionary.
I an doing this in python 3.7, which preserves element order in dictionaries. Is there a function that would do this or what code would allow me to do this.

you can convert to a list dict1.items then use the built-in function reversed:
dict(reversed(list(dict1.items())))
output:
{'d': 'gh', 2: 'c', 1: 'a'}

You can use reversed() to reverse the dictionary:
>>> dict1 = {1:'a', 2:'c', 'd':'gh'}
>>> dict2 = dict(reversed(dict1.items()))
>>> dict2
{'d': 'gh', 2: 'c', 1: 'a'}
As #kederrac helpfully pointed out in the comments, the above won't work in Python 3.7, only 3.8. It will trigger a TypeError: 'dict_items' object is not reversible exception. To fix this you will need to cast list() to dict1.items(), as shown in #kederrac's answer. Its probably safe to do this for safer, portable code anyways.

Related

Cannot rename Python dict key values with pop - Bug?

I cannot rename the Python dict using pop as described below. I've used suggestions from this post. Is this a Python bug? I'm using Python 3.5.2
>>> d = {'a': 'ABC', 'b': 'CDE', 'c': 'KRT'}
>>> for old_key in d.keys():
d['NEW_KEY_' + old_key] = d.pop(old_key)
>>> d
{'NEW_KEY_NEW_KEY_NEW_KEY_b': 'CDE', 'NEW_KEY_NEW_KEY_a': 'ABC', 'c': 'KRT'}
In Python 3, you have to change for old_key in d.keys() into for old_key in list(d.keys()). That should work because you are iterating over a dynamic entity.
It's mentioned in the documentation that changing a dictionary while iterating over it might fail to produce correct results. You'd better write something like
new_dict = {'NEW_KEY_' + key: value for key, value in old_dict.items()}
You are changing your keys as you iterate over a view of them. That's not recommended.
Instead, you can take a copy of your keys and iterate over them. Since dictionary keys are unique, you can use list or set:
d = {'a': 'ABC', 'b': 'CDE', 'c': 'KRT'}
for old_key in list(d):
d['NEW_KEY_' + old_key] = d.pop(old_key)
# {'NEW_KEY_a': 'ABC', 'NEW_KEY_b': 'CDE', 'NEW_KEY_c': 'KRT'}
You can, of course, use a dictionary comprehension, which you should find more efficient.

Python: Dictionary changing

For some reason when I modify mydict2 it changes the contents of mydict
Here is my code:
mydict = {1:'a', 2:'b'}
mydict2 = mydict
mydict2[1] = 'c'
print(mydict2)
If you try this, it outputs {1: 'c', 2: 'b'}
It should output {1: 'a', 2: 'b'} and when you do print(mydict) it should output {1: 'c', 2: 'b'}
mydict and mydict2 are both pointing to the same object in memory. When either one changes, the other does as well. They references to the same dictionary.
It is not enough to use the assignment operator to make a proper copy. If you want mydict2 to point to a copy of the dictionary mydict points to, you need to tell Python to explicitly make a copy:
>>> mydict = {1:'a', 2:'b'}
>>> mydict2 = mydict.copy()
>>> mydict2[1] = 'c'
>>> mydict
{1: 'a', 2: 'b'}
>>> mydict2
{1: 'c', 2: 'b'}
>>>
Note however that this method will fail if you have a nested dictionary structure. You'd need to use copy.deepcopy() in that case.
mydict and mydict2 are both references to the same object.
So changes to mydict or mydict2 will change the same object, and therefore it looks like changing one of them is changing the other.
You are setting mydic2 equal to the object mydict. When you mutate mydict2, it will change the contents of mydict1.
Try using copy or copy.deepcopy as seen here: python docs
See this thread for an example: stackoverflow thread
You should use function copy:
from copy import copy
mydict = {1:'a', 2:'b'}
mydict2 = copy(mydict)
mydict2[1] = 'c'
print(mydict2)
There are two links for the same object. If you want to have two objects, you should copy your dict
mydict and mydict2 both reference the same dictionary, so when you change one, you change the other one too.

using a single variable to index into nested dictionaries

Imagine you have a dictionary in python: myDic = {'a':1, 'b':{'c':2, 'd':3}}. You can certainly set a variable to a key value and use it later, such as:
myKey = 'b'
myDic[myKey]
>>> {'c':2, 'd':3}
However, is there a way to somehow set a variable to a value that, when used as a key, will dig into sub dictionaries as well? Is there a way to accomplish the following pseudo-code in python?
myKey = "['b']['c']"
myDic[myKey]
>>> 2
So first it uses 'b' as a key, and whatever is reurned it then uses 'c' as a key on that. Obviously, it would return an error if the value returned from the first lookup is not a dictionary.
No, there is nothing you can put into a variable so that myDict[myKey] will dig into the nested dictionaries.
Here is a function that may work for you as an alternative:
def recursive_get(d, keys):
if len(keys) == 1:
return d[keys[0]]
return recursive_get(d[keys[0]], keys[1:])
Example:
>>> myDic = {'a':1, 'b':{'c':2, 'd':3}}
>>> recursive_get(myDic, ['b', 'c'])
2
No, not with a regular dict. With myDict[key] you can only access values that are actually values of myDict. But if myDict contains other dicts, the values of those nested dicts are not values of myDict.
Depending on what you're doing with the data structure, it may be possible to get what you want by using tuple keys instead of nested dicts. Instead of having myDic = {'b':{'c':2, 'd':3}}, you could have myDic = {('b', 'c'):2, ('b', 'd'): 3}. Then you can access the values with something like myDic['b', 'c']. And you can indeed do:
val = 'b', 'c'
myDic[val]
AFAIK, you cannot. If you think about the way python works, it evaluates inside out, left to right. [] is a shorthand for __getitem__ in this case. Thus you would need to parse the arguments you are passing into __getitem__ (whatever you pass in) and handle that intelligently. If you wanted to have such behavior, you would need to subclass/write your own dict class.
myDict = {'a':1, 'b':{'c':2, 'd':3}}
k = 'b'
myDict.get(k) should give
{'c':2, 'd':3}
and either
d.get(k)['c']
OR
k1 = 'c'
d.get(k).key(k1) should give 2
Pretty old question. There is no builtin function for that.
Compact solution using functools.reduce and operator.getitem:
from functools import reduce
from operator import getitem
d = {'a': {'b': ['banana', 'lemon']}}
p = ['a', 'b', 1]
v = reduce(getitem, p, d)
# 'lemon'

Python dictionary.keys() error

I am trying to use the .keys() and instead of getting a list of the keys like
always have in the past. However I get this.
b = { 'video':0, 'music':23 }
k = b.keys()
print( k[0] )
>>>TypeError: 'dict_keys' object does not support indexing
print( k )
dict_keys(['music', 'video'])
it should just print ['music', 'video'] unless I'm going crazy.
What's going on?
Python 3 changed the behavior of dict.keys such that it now returns a dict_keys object, which is iterable but not indexable (it's like the old dict.iterkeys, which is gone now). You can get the Python 2 result back with an explicit call to list:
>>> b = { 'video':0, 'music':23 }
>>> k = list(b.keys())
>>> k
['music', 'video']
or just
>>> list(b)
['music', 'video']
If you assigned k like so:
k = list(b.keys())
your code will work.
As the error says, the dict_keys type does not support indexing.
This is one of the breaking changes between Python 2 and 3.
In Python 2:
>>> help(dict.keys)
keys(...)
D.keys() -> list of D's keys
In Python 3:
>>> help(dict.keys)
keys(...)
D.keys() -> a set-like object providing a view on D's keys
This change in behavior makes a lot of sense since a dict is semantically unordered and its keys are unique - just like a set.
This change means that you don't have to create a new list of keys every time you want to do some kind of set comparison with a dict's keys.
Getting the same behavior in 2 and 3
To help transition to Python 3, Python 2.7 has another dict method, viewkeys. The viewkeys method is most similar to Python 3's dict.keys method:
>>> d
{'a': None, 'c': None, 'b': None, 'd': None}
>>> for k in d.viewkeys(): print k
...
a
c
b
d
>>> d.viewkeys() & set('abc')
set(['a', 'c', 'b'])
In Python 3, the closest analog to the old behavior is to pass dict.keys() to list:
>>> d
{'d': None, 'a': None, 'c': None, 'b': None}
>>> list(d.keys())
['d', 'a', 'c', 'b']
Or just pass the dict to list, since a dict will iterate over its keys anyways:
>>> list(d)
['d', 'a', 'c', 'b']
You could create a utility functions to abstract the behavior over 2 and 3:
if hasattr(dict, 'viewkeys'): # Python 2.7
def keys(d):
return d.viewkeys()
else: # Python 3
def keys(d):
return d.keys()
And pass a dict to list to get the list form, and in both 2 and 3, you'll get the same output:
>>> d
{'b': None, 'a': None, 'c': None, 'd': None}
>>> keys(d)
dict_keys(['b', 'a', 'c', 'd'])
>>> list(d)
['b', 'a', 'c', 'd']
If you simply want a list of keys from a dictionary you can directly do like this:
b = {"name": "xyz", "class":"abc", "college": "qwert"}
key_list = list(b)
key_list will contain all the key names as a list, though, this will not repeats a key, if found more than once. Duplicate keys will be counted as one.
import random
b = { 'video':0, 'music':23,"picture":12 }
random.choice(tuple(b.items()))
# Returns a random dictionary entry as a tuple:
# ('music', 23)

Pick a key from a dictionary python

go through a dictionary picking keys from it in a loop?
For example lets say I have the following dictionary: {'hello':'world', 'hi':'there'}. Is there a way to for loop through the dictionary and print hello, hi?
on a similar note is there a way to say myDictionary.key[1] and that will return hi?
You can iterate over the keys of a dict with a for loop:
>>> for key in yourdict:
>>> print(key)
hi
hello
If you want them as a comma separated string you can use ', '.join.
>>> print(', '.join(yourdict))
hi, hello
on a similar note is there a way to say myDictionary.key1 and that will return hi
No. The keys in a dictionary are not in any particular order. The order that you see when you iterate over them may not be the same as the order you inserted them into the dictionary, and also the order could in theory change when you add or remove items.
if you need an ordered collection you might want to consider using another type such as a list, or an OrderedDict
You can use the .keys() method:
for key in myDictionary.keys():
print(key)
You can also use .items() to iterate through both at the same time:
for key, value in myDictionary.items():
print(key, value)
Using the dictionary name as a sequence produces all the keys:
>>> d={'hello':'world', 'hi':'there'}
>>> list(d)
['hi', 'hello']
so list({'hello':'world', 'hi':'there'})[1] produces element 1 of the list of keys.
This is of limited use, however, because dictionaries are unordered. And their order may be different than the order of insertion:
>>> d={'a': 'ahh', 'b': 'baa', 'c': 'coconut'}
>>> d
{'a': 'ahh', 'c': 'coconut', 'b': 'baa'}
You can do sorted(list({'hello':'world', 'hi':'there'}))[1] for the 1 element of a sorted list of the keys of your dict. That produces 'hi' in this case. Not the most readable or efficient though...
You should look at OrderedDict if you want a sorted order.
Or just sort into a list:
>>> d={'a': 'ahh', 'b': 'baa', 'c': 'coconut'}
>>> l=[(k,v) for k, v in d.items()]
>>> l.sort()
>>> l[1]
('b', 'baa')
>>> l[1][0]
'b'
You can reverse (k,v) to (v,k) if you want to sort by value instead of by key.
dict.iterkeys in Python 2, dict.keys in Python 3.
d = { 'hello': 'world', 'hi': 'there' }
for key in d.iterkeys():
print key
Sounds like a list of keys would meet your needs:
>>> d = { 'hello': 'world', 'hi': 'there' }
>>> keys = list(d)
>>> keys
['hi', 'hello']
>>> from random import choice
>>> choice(keys)
'hi'

Categories

Resources