How to convert an OrderedDict into a regular dict in python3 - python

I am struggling with the following problem:
I want to convert an OrderedDict like this:
OrderedDict([('method', 'constant'), ('data', '1.225')])
into a regular dict like this:
{'method': 'constant', 'data':1.225}
because I have to store it as string in a database. After the conversion the order is not important anymore, so I can spare the ordered feature anyway.
Thanks for any hint or solutions,
Ben

>>> from collections import OrderedDict
>>> OrderedDict([('method', 'constant'), ('data', '1.225')])
OrderedDict([('method', 'constant'), ('data', '1.225')])
>>> dict(OrderedDict([('method', 'constant'), ('data', '1.225')]))
{'data': '1.225', 'method': 'constant'}
>>>
However, to store it in a database it'd be much better to convert it to a format such as JSON or Pickle. With Pickle you even preserve the order!

Even though this is a year old question, I would like to say that using dict will not help if you have an ordered dict within the ordered dict. The simplest way that could convert those recursive ordered dict will be
import json
from collections import OrderedDict
input_dict = OrderedDict([('method', 'constant'), ('recursive', OrderedDict([('m', 'c')]))])
output_dict = json.loads(json.dumps(input_dict))
print output_dict

It is easy to convert your OrderedDict to a regular Dict like this:
dict(OrderedDict([('method', 'constant'), ('data', '1.225')]))
If you have to store it as a string in your database, using JSON is the way to go. That is also quite simple, and you don't even have to worry about converting to a regular dict:
import json
d = OrderedDict([('method', 'constant'), ('data', '1.225')])
dString = json.dumps(d)
Or dump the data directly to a file:
with open('outFile.txt','w') as o:
json.dump(d, o)

If you are looking for a recursive version without using the json module:
def ordereddict_to_dict(value):
for k, v in value.items():
if isinstance(v, dict):
value[k] = ordereddict_to_dict(v)
return dict(value)

Here is what seems simplest and works in python 3.7
from collections import OrderedDict
d = OrderedDict([('method', 'constant'), ('data', '1.225')])
d2 = dict(d) # Now a normal dict
Now to check this:
>>> type(d2)
<class 'dict'>
>>> isinstance(d2, OrderedDict)
False
>>> isinstance(d2, dict)
True
NOTE: This also works, and gives same result -
>>> {**d}
{'method': 'constant', 'data': '1.225'}
>>> {**d} == d2
True
As well as this -
>>> dict(d)
{'method': 'constant', 'data': '1.225'}
>>> dict(d) == {**d}
True
Cheers

You can use "dict_constructor" parameters.
xmltodict.parse(text, attr_prefix='',dict_constructor=dict)

If your data structure might contain internal (nested) OrderedDict instances, you should leverage Python's builtin copy mechanism.
You can override copying behavior for OrderedDict via Python's copyreg module (also used by pickle). Then you can use Python's builtin copy.deepcopy() function to perform the conversion.
import copy
import copyreg
from collections import OrderedDict
def convert_nested_ordered_dict(x):
"""
Perform a deep copy of the given object, but convert
all internal OrderedDicts to plain dicts along the way.
Args:
x: Any pickleable object
Returns:
A copy of the input, in which all OrderedDicts contained
anywhere in the input (as iterable items or attributes, etc.)
have been converted to plain dicts.
"""
# Temporarily install a custom pickling function
# (used by deepcopy) to convert OrderedDict to dict.
orig_pickler = copyreg.dispatch_table.get(OrderedDict, None)
copyreg.pickle(
OrderedDict,
lambda d: (dict, ([*d.items()],))
)
try:
return copy.deepcopy(x)
finally:
# Restore the original OrderedDict pickling function (if any)
del copyreg.dispatch_table[OrderedDict]
if orig_pickler:
copyreg.dispatch_table[OrderedDict] = orig_pickler
Merely by using Python's builtin copying infrastructure, this solution is superior to all other answers presented here, in the following ways:
Works for arbitrary data hierarchies, including nested OrderedDicts.
Works for more than just JSON data.
Does not require you to implement special logic for each possible element type (e.g. list, tuple, etc.)
deepcopy() will properly handle duplicate objects within the collection:
x = [1,2,3]
d = {'a': x, 'b': x}
assert d['a'] is d['b']
d2 = copy.deepcopy(d)
assert d2['a'] is d2['b']
Since our solution is based on deepcopy() we'll have the same advantage.
This solution also converts attributes that happen to be OrderedDict, not only collection elements:
class C:
def __init__(self, a):
self.a = a
def __repr__(self):
return f"C(a={self.a})"
c = C(OrderedDict([(1, 'one'), (2, 'two')]))
print("original: ", c)
print("converted:", convert_nested_ordered_dict(c))
original: C(a=OrderedDict([(1, 'one'), (2, 'two')]))
converted: C(a={1: 'one', 2: 'two'})

Its simple way
>>import json
>>from collection import OrderedDict
>>json.dumps(dict(OrderedDict([('method', 'constant'), ('data', '1.225')])))

A version that handles nested dictionaries and iterables but does not use the json module. Nested dictionaries become dict, nested iterables become list, everything else is returned unchanged (including dictionary keys and strings/bytes/bytearrays).
def recursive_to_dict(obj):
try:
if hasattr(obj, "split"): # is string-like
return obj
elif hasattr(obj, "items"): # is dict-like
return {k: recursive_to_dict(v) for k, v in obj.items()}
else: # is iterable
return [recursive_to_dict(e) for e in obj]
except TypeError: # return everything else
return obj

Related

Remove JSON data pairs from nested structure [duplicate]

I had to remove some fields from a dictionary, the keys for those fields are on a list. So I wrote this function:
def delete_keys_from_dict(dict_del, lst_keys):
"""
Delete the keys present in lst_keys from the dictionary.
Loops recursively over nested dictionaries.
"""
dict_foo = dict_del.copy() #Used as iterator to avoid the 'DictionaryHasChanged' error
for field in dict_foo.keys():
if field in lst_keys:
del dict_del[field]
if type(dict_foo[field]) == dict:
delete_keys_from_dict(dict_del[field], lst_keys)
return dict_del
This code works, but it's not very elegant and I'm sure that there is a better solution.
First of, I think your code is working and not inelegant. There's no immediate reason not to use the code you presented.
There are a few things that could be better though:
Comparing the type
Your code contains the line:
if type(dict_foo[field]) == dict:
That can be definitely improved. Generally (see also PEP8) you should use isinstance instead of comparing types:
if isinstance(dict_foo[field], dict)
However that will also return True if dict_foo[field] is a subclass of dict. If you don't want that, you could also use is instead of ==. That will be marginally (and probably unnoticeable) faster.
If you also want to allow arbitary dict-like objects you could go a step further and test if it's a collections.abc.MutableMapping. That will be True for dict and dict subclasses and for all mutable mappings that explicitly implement that interface without subclassing dict, for example UserDict:
>>> from collections import MutableMapping
>>> # from UserDict import UserDict # Python 2.x
>>> from collections import UserDict # Python 3.x - 3.6
>>> # from collections.abc import MutableMapping # Python 3.7+
>>> isinstance(UserDict(), MutableMapping)
True
>>> isinstance(UserDict(), dict)
False
Inplace modification and return value
Typically functions either modify a data structure inplace or return a new (modified) data structure. Just to mention a few examples: list.append, dict.clear, dict.update all modify the data structure inplace and return None. That makes it easier to keep track what a function does. However that's not a hard rule and there are always valid exceptions from this rule. However personally I think a function like this doesn't need to be an exception and I would simply remove the return dict_del line and let it implicitly return None, but YMMV.
Removing the keys from the dictionary
You copied the dictionary to avoid problems when you remove key-value pairs during the iteration. However, as already mentioned by another answer you could just iterate over the keys that should be removed and try to delete them:
for key in keys_to_remove:
try:
del dict[key]
except KeyError:
pass
That has the additional advantage that you don't need to nest two loops (which could be slower, especially if the number of keys that need to be removed is very long).
If you don't like empty except clauses you can also use: contextlib.suppress (requires Python 3.4+):
from contextlib import suppress
for key in keys_to_remove:
with suppress(KeyError):
del dict[key]
Variable names
There are a few variables I would rename because they are just not descriptive or even misleading:
delete_keys_from_dict should probably mention the subdict-handling, maybe delete_keys_from_dict_recursive.
dict_del sounds like a deleted dict. I tend to prefer names like dictionary or dct because the function name already describes what is done to the dictionary.
lst_keys, same there. I'd probably use just keys there. If you want to be more specific something like keys_sequence would make more sense because it accepts any sequence (you just have to be able to iterate over it multiple times), not just lists.
dict_foo, just no...
field isn't really appropriate either, it's a key.
Putting it all together:
As I said before I personally would modify the dictionary in-place and not return the dictionary again. Because of that I present two solutions, one that modifies it in-place but doesn't return anything and one that creates a new dictionary with the keys removed.
The version that modifies in-place (very much like Ned Batchelders solution):
from collections import MutableMapping
from contextlib import suppress
def delete_keys_from_dict(dictionary, keys):
for key in keys:
with suppress(KeyError):
del dictionary[key]
for value in dictionary.values():
if isinstance(value, MutableMapping):
delete_keys_from_dict(value, keys)
And the solution that returns a new object:
from collections import MutableMapping
def delete_keys_from_dict(dictionary, keys):
keys_set = set(keys) # Just an optimization for the "if key in keys" lookup.
modified_dict = {}
for key, value in dictionary.items():
if key not in keys_set:
if isinstance(value, MutableMapping):
modified_dict[key] = delete_keys_from_dict(value, keys_set)
else:
modified_dict[key] = value # or copy.deepcopy(value) if a copy is desired for non-dicts.
return modified_dict
However it only makes copies of the dictionaries, the other values are not returned as copy, you could easily wrap these in copy.deepcopy (I put a comment in the appropriate place of the code) if you want that.
def delete_keys_from_dict(dict_del, lst_keys):
for k in lst_keys:
try:
del dict_del[k]
except KeyError:
pass
for v in dict_del.values():
if isinstance(v, dict):
delete_keys_from_dict(v, lst_keys)
return dict_del
Since the question requested an elegant way, I'll submit my general-purpose solution to wrangling nested structures. First, install the boltons utility package with pip install boltons, then:
from boltons.iterutils import remap
data = {'one': 'remains', 'this': 'goes', 'of': 'course'}
bad_keys = set(['this', 'is', 'a', 'list', 'of', 'keys'])
drop_keys = lambda path, key, value: key not in bad_keys
clean = remap(data, visit=drop_keys)
print(clean)
# Output:
{'one': 'remains'}
In short, the remap utility is a full-featured, yet succinct approach to handling real-world data structures which are often nested, and can even contain cycles and special containers.
This page has many more examples, including ones working with much larger objects from Github's API.
It's pure-Python, so it works everywhere, and is fully tested in Python 2.7 and 3.3+. Best of all, I wrote it for exactly cases like this, so if you find a case it doesn't handle, you can bug me to fix it right here.
def delete_keys_from_dict(d, to_delete):
if isinstance(to_delete, str):
to_delete = [to_delete]
if isinstance(d, dict):
for single_to_delete in set(to_delete):
if single_to_delete in d:
del d[single_to_delete]
for k, v in d.items():
delete_keys_from_dict(v, to_delete)
elif isinstance(d, list):
for i in d:
delete_keys_from_dict(i, to_delete)
d = {'a': 10, 'b': [{'c': 10, 'd': 10, 'a': 10}, {'a': 10}], 'c': 1 }
delete_keys_from_dict(d, ['a', 'c']) # inplace deletion
print(d)
>>> {'b': [{'d': 10}, {}]}
This solution works for dict and list in a given nested dict. The input to_delete can be a list of str to be deleted or a single str.
Plese note, that if you remove the only key in a dict, you will get an empty dict.
I think the following is more elegant:
def delete_keys_from_dict(dict_del, lst_keys):
if not isinstance(dict_del, dict):
return dict_del
return {
key: value
for key, value in (
(key, delete_keys_from_dict(value, lst_keys))
for key, value in dict_del.items()
)
if key not in lst_keys
}
Example usage:
test_dict_in = {
1: {1: {0: 2, 3: 4}},
0: {2: 3},
2: {5: {0: 4}, 6: {7: 8}},
}
test_dict_out = {
1: {1: {3: 4}},
2: {5: {}, 6: {7: 8}},
}
assert delete_keys_from_dict(test_dict_in, [0]) == test_dict_out
Since you already need to loop through every element in the dict, I'd stick with a single loop and just make sure to use a set for looking up the keys to delete
def delete_keys_from_dict(dict_del, the_keys):
"""
Delete the keys present in the lst_keys from the dictionary.
Loops recursively over nested dictionaries.
"""
# make sure the_keys is a set to get O(1) lookups
if type(the_keys) is not set:
the_keys = set(the_keys)
for k,v in dict_del.items():
if k in the_keys:
del dict_del[k]
if isinstance(v, dict):
delete_keys_from_dict(v, the_keys)
return dict_del
this works with dicts containing Iterables (list, ...) that may contain dict. Python 3. For Python 2 unicode should also be excluded from the iteration. Also there may be some iterables that don't work that I'm not aware of. (i.e. will lead to inifinite recursion)
from collections.abc import Iterable
def deep_omit(d, keys):
if isinstance(d, dict):
for k in keys:
d.pop(k, None)
for v in d.values():
deep_omit(v, keys)
elif isinstance(d, Iterable) and not isinstance(d, str):
for e in d:
deep_omit(e, keys)
return d
Since nobody posted an interactive version that could be useful for someone:
def delete_key_from_dict(adict, key):
stack = [adict]
while stack:
elem = stack.pop()
if isinstance(elem, dict):
if key in elem:
del elem[key]
for k in elem:
stack.append(elem[k])
This version is probably what you would push to production. The recursive version is elegant and easy to write but it scales badly (by default Python uses a maximum recursion depth of 1000).
If you have nested keys as well and based on #John La Rooy's answer here is an elegant solution:
from boltons.iterutils import remap
def sof_solution():
data = {"user": {"name": "test", "pwd": "******"}, "accounts": ["1", "2"]}
sensitive = {"user.pwd", "accounts"}
clean = remap(
data,
visit=lambda path, key, value: drop_keys(path, key, value, sensitive)
)
print(clean)
def drop_keys(path, key, value, sensitive):
if len(path) > 0:
nested_key = f"{'.'.join(path)}.{key}"
return nested_key not in sensitive
return key not in sensitive
sof_solution() # prints {'user': {'name': 'test'}}
Using the awesome code from this post and add a small statement:
def remove_fields(self, d, list_of_keys_to_remove):
if not isinstance(d, (dict, list)):
return d
if isinstance(d, list):
return [v for v in (self.remove_fields(v, list_of_keys_to_remove) for v in d) if v]
return {k: v for k, v in ((k, self.remove_fields(v, list_of_keys_to_remove)) for k, v in d.items()) if k not in list_of_keys_to_remove}
I came here to search for a solution to remove keys from deeply nested Python3 dicts and all solutions seem to be somewhat complex.
Here's a oneliner for removing keys from nested or flat dicts:
nested_dict = {
"foo": {
"bar": {
"foobar": {},
"shmoobar": {}
}
}
}
>>> {'foo': {'bar': {'foobar': {}, 'shmoobar': {}}}}
nested_dict.get("foo", {}).get("bar", {}).pop("shmoobar", None)
>>> {'foo': {'bar': {'foobar': {}}}}
I used .get() to not get KeyError and I also provide empty dict as default value up to the end of the chain. I do pop() for the last element and I provide None as the default there to avoid KeyError.

Pythonic way to convert a dictionary into namedtuple or another hashable dict-like?

I have a dictionary like:
d = {'a': 1, 'b': 2, 'c': 3, 'd': 4}
which I would like to convert to a namedtuple.
My current approach is with the following code
namedTupleConstructor = namedtuple('myNamedTuple', ' '.join(sorted(d.keys())))
nt= namedTupleConstructor(**d)
which produces
myNamedTuple(a=1, b=2, c=3, d=4)
This works fine for me (I think), but am I missing a built-in such as...
nt = namedtuple.from_dict() ?
UPDATE: as discussed in the comments, my reason for wanting to convert my dictionary to a namedtuple is so that it becomes hashable, but still generally useable like a dict.
UPDATE2: 4 years after I've posted this question, TLK posts a new answer recommending using the dataclass decorator that I think is really great. I think that's now what I would use going forward.
To create the subclass, you may just pass the keys of a dict directly:
MyTuple = namedtuple('MyTuple', d)
Now to create tuple instances from this dict, or any other dict with matching keys:
my_tuple = MyTuple(**d)
Beware: namedtuples compare on values only (ordered). They are designed to be a drop-in replacement for regular tuples, with named attribute access as an added feature. The field names will not be considered when making equality comparisons. It may not be what you wanted nor expected from the namedtuple type! This differs from dict equality comparisons, which do take into account the keys and also compare order agnostic.
For readers who don't really need a type which is a subclass of tuple, there probably isn't much point to use a namedtuple in the first place. If you just want to use attribute access syntax on fields, it would be simpler and easier to create namespace objects instead:
>>> from types import SimpleNamespace
>>> SimpleNamespace(**d)
namespace(a=1, b=2, c=3, d=4)
my reason for wanting to convert my dictionary to a namedtuple is so that it becomes hashable, but still generally useable like a dict
For a hashable "attrdict" like recipe, check out a frozen box:
>>> from box import Box
>>> b = Box(d, frozen_box=True)
>>> hash(b)
7686694140185755210
>>> b.a
1
>>> b["a"]
1
>>> b["a"] = 2
BoxError: Box is frozen
There may also be a frozen mapping type coming in a later version of Python, watch this draft PEP for acceptance or rejection:
PEP 603 -- Adding a frozenmap type to collections
from collections import namedtuple
nt = namedtuple('x', d.keys())(*d.values())
If you want an easier approach, and you have the flexibility to use another approach other than namedtuple I would like to suggest using SimpleNamespace (docs).
from types import SimpleNamespace as sn
d = {'a': 1, 'b': 2, 'c': 3, 'd': 4}
dd= sn(**d)
# dd.a>>1
# add new property
dd.s = 5
#dd.s>>5
PS: SimpleNamespace is a type, not a class
I'd like to recommend the dataclass for this type of situation. Similar to a namedtuple, but with more flexibility.
https://docs.python.org/3/library/dataclasses.html
from dataclasses import dataclass
#dataclass
class InventoryItem:
"""Class for keeping track of an item in inventory."""
name: str
unit_price: float
quantity_on_hand: int = 0
def total_cost(self) -> float:
return self.unit_price * self.quantity_on_hand
You can use this function to handle nested dictionaries:
def create_namedtuple_from_dict(obj):
if isinstance(obj, dict):
fields = sorted(obj.keys())
namedtuple_type = namedtuple(
typename='GenericObject',
field_names=fields,
rename=True,
)
field_value_pairs = OrderedDict(
(str(field), create_namedtuple_from_dict(obj[field]))
for field in fields
)
try:
return namedtuple_type(**field_value_pairs)
except TypeError:
# Cannot create namedtuple instance so fallback to dict (invalid attribute names)
return dict(**field_value_pairs)
elif isinstance(obj, (list, set, tuple, frozenset)):
return [create_namedtuple_from_dict(item) for item in obj]
else:
return obj
use the dictionary keys as the fieldnames to the namedtuple
d = {'a': 1, 'b': 2, 'c': 3, 'd': 4}
def dict_to_namedtuple(d):
return namedtuple('GenericDict', d.keys())(**d)
result=dict_to_namedtuple(d)
print(result)
output
GenericDict(a=1, b=2, c=3, d=4)
def toNametuple(dict_data):
return namedtuple(
"X", dict_data.keys()
)(*tuple(map(lambda x: x if not isinstance(x, dict) else toNametuple(x), dict_data.values())))
d = {
'id': 1,
'name': {'firstName': 'Ritesh', 'lastName':'Dubey'},
'list_data': [1, 2],
}
obj = toNametuple(d)
Access as obj.name.firstName, obj.id
This will work for nested dictionary with any data types.
I find the following 4-liner the most beautiful. It supports nested dictionaries as well.
def dict_to_namedtuple(typename, data):
return namedtuple(typename, data.keys())(
*(dict_to_namedtuple(typename + '_' + k, v) if isinstance(v, dict) else v for k, v in data.items())
)
The output will look good also:
>>> nt = dict_to_namedtuple('config', {
... 'path': '/app',
... 'debug': {'level': 'error', 'stream': 'stdout'}
... })
>>> print(nt)
config(path='/app', debug=config_debug(level='error', stream='stdout'))
Check this out:
def fill_tuple(NamedTupleType, container):
if container is None:
args = [None] * len(NamedTupleType._fields)
return NamedTupleType(*args)
if isinstance(container, (list, tuple)):
return NamedTupleType(*container)
elif isinstance(container, dict):
return NamedTupleType(**container)
else:
raise TypeError("Cannot create '{}' tuple out of {} ({}).".format(NamedTupleType.__name__, type(container).__name__, container))
Exceptions for incorrect names or invalid argument count is handled by __init__ of namedtuple.
Test with py.test:
def test_fill_tuple():
A = namedtuple("A", "aa, bb, cc")
assert fill_tuple(A, None) == A(aa=None, bb=None, cc=None)
assert fill_tuple(A, [None, None, None]) == A(aa=None, bb=None, cc=None)
assert fill_tuple(A, [1, 2, 3]) == A(aa=1, bb=2, cc=3)
assert fill_tuple(A, dict(aa=1, bb=2, cc=3)) == A(aa=1, bb=2, cc=3)
with pytest.raises(TypeError) as e:
fill_tuple(A, 2)
assert e.value.message == "Cannot create 'A' tuple out of int (2)."
Although I like #fuggy_yama answer, before read it I got my own function, so I leave it here just to show a different approach. It also handles nested namedtuples
def dict2namedtuple(thedict, name):
thenametuple = namedtuple(name, [])
for key, val in thedict.items():
if not isinstance(key, str):
msg = 'dict keys must be strings not {}'
raise ValueError(msg.format(key.__class__))
if not isinstance(val, dict):
setattr(thenametuple, key, val)
else:
newname = dict2namedtuple(val, key)
setattr(thenametuple, key, newname)
return thenametuple

How to sort a dictionary in Python with keys of mixed letters and numbers?

I have a dictionary like this:
dict_str = {'Number_1_item':'foo',
'Number_11_item':'bar',
'Number_22_item':'foobar',
'Number_5_item':'barfoo'}
And my desired out put is:
sorted_dict_str = {'Number_1_item':'foo',
'Number_5_item':'bar',
'Number_11_item':'foobar',
'Number_22_item':'barfoo'}
So the sorted_dict_str is sorted in numerical way based on the keys in dict_str.
I have found some answers to sort the keys with pure numeric keys but not mixed ones, so they are not really helpful.
Thanks a lot.
Regards
You can get sorted dict from your dict like that:
from collections import OrderedDict
OrderedDict(sorted(dict_str.items(), key=lambda s: int(s[0].split('_')[1])))
If we can assume that all the keys are on the format Number_XX_item, you could simply sort on the numeric part, using a lambda:
sorted_dict_str = sorted(dict_str.items(), key=lambda x: int(x[0].split('_')[1]))
This gives the following output:
sorted_dict_str =
[('Number_1_item', 'foo'),
('Number_5_item', 'barfoo'),
('Number_11_item', 'bar'),
('Number_22_item', 'foobar')]
Yet another solution. When executing the sorted function it'll return a sorted list of all the keys in the dictionary. A dictionary can't be sorted (though there is a way of having an ordered dictionary).
This Solution is also more robust compared to the first solution, since the number can be anywhere in the key.
import re
from collections import OrderedDict
d = {'Number_1_item':'foo',
'Number_11_item':'bar',
'Number_22_item':'foobar',
'Number_5_item':'barfoo'}
keys = d.keys()
def sort_mixed(key):
int_match = re.search(r'(?P<int>\d+)', key)
number = int_match.group(0)
return int(number)
sorted_keys = sorted(keys, key=lambda key: sort_mixed(key))
print(sorted_keys) # print sorted keys
sorted_dict = OrderedDict((k, d[k]) for k in sorted_keys)
print(sorted_dict) # print new sorted dict
You should check out natsort. There are ways to do it by yourself, without importing extra modules, but I like is method.
>>> from collections import OrderedDict
>>> import natsort
>>> input_dict = {'Number_1_item':'foo', 'Number_11_item':'bar', 'Number_22_item':'foobar', 'Number_5_item':'barfoo'}
>>> OrderedDict(natsort.natsorted(input_dict.items()))
OrderedDict([('Number_1_item', 'foo'), ('Number_5_item', 'barfoo'), ('Number_11_item', 'bar'), ('Number_22_item', 'foobar')])
Here's a solution using the slicing technique I mentioned in the comments. This is less robust than using .split, since the lengths of the prefix & suffix strings are hard-coded, but it's slightly faster because slicing is fast compared to a method call.
from collections import OrderedDict
from pprint import pprint
dict_str = {
'Number_1_item':'foo',
'Number_11_item':'bar',
'Number_22_item':'foobar',
'Number_5_item':'barfoo',
}
skeys = sorted(dict_str.keys(), key=lambda s: int(s[7:][:-5]))
sorted_dict = OrderedDict((k, dict_str[k]) for k in skeys)
pprint(sorted_dict)
output
OrderedDict([('Number_1_item', 'foo'),
('Number_5_item', 'barfoo'),
('Number_11_item', 'bar'),
('Number_22_item', 'foobar')])
You could also do the sorting on the (key, value) pairs inside the OrderedDict constructor call:
sorted_dict = OrderedDict(sorted(dict_str.items(), key=lambda u: int(u[0][7:][:-5])))
but I think my previous version is a little more readable.
You can sort the keys of a dictionary into a list, with the additional key-Argument:
dict_str = {'Number_1_item':'foo',
'Number_11_item':'bar',
'Number_22_item':'foobar',
'Number_5_item':'barfoo'}
sorted_keys = sorted(dict_str, key=lambda x: int(x.split('_')[1]))
You can't sort the dict itself by definition of what a dict is.
But you can sort its keys in any custom order by passing the desired 'key' argument into sorted function
sorted(iterable[, cmp[, key[, reverse]]])
https://docs.python.org/2/library/functions.html#sorted

Python copying defaultdict to dict with new order of key

I have a defaultdict with unsorted by key values:
d = defaultdict(int)
...
defaultdict(<type 'int'>, {'2014-06-30': 2, '2013-04-18': 7, '2013-04-19': 9})
Sort list of keys:
tmp = sorted(d.keys())
And create new dict:
nd = {}
for i in tmp:
nd[i] = d[i]
But as a result I am getting exact copy of source dict.
Although I added elements in new order.
dict instances are arbitrarily ordered. If you want a specific order then use collections.OrderedDict instead.
from collections import OrderedDict
ord_dict = OrderedDict()
for i in tmp:
ord_dict[i] = d[i]
print(ord_dict)
OrderedDict([('2013-04-18', 7), ('2013-04-19', 9), ('2014-06-30', 2)])
Or as #jon Clements suggests simply:
OrderedDict(sorted(d.iteritems()))
Or OrderedDict(sorted(d.items())) using python 3
python dictionaries does not work that way. Dictionary is actually a hash map which means values are put in a spot in dict depending on key hash, not the order you put your item and when iterating, you will not get "ordered dict". Use OrderedDict class instead

why dict objects are unhashable in python?

I mean why cant we put key of dict as dict?
that means we can't have dictionary having key as another dictionary...
Short answer: because they are mutable containers.
If a dict was hashed, its hash would change as you changed its contents.
This is easy to deal with. Wrap a dict in a frozenset before you hash it. Then, when you need to use it, convert it back to a dict.
>>> unhashable = {'b': 'a', 'a': 'b'}
>>> hashable = frozenset(unhashable.items())
>>> unhashable = dict(hashable)
>>> unhashable
{'a': 'b', 'b': 'a'}
Note that dictionary key order is undefined anyway, so the change in key order doesn't matter.
As others have said, the hash value of a dict changes as the contents change.
However if you really need to use dicts as keys, you can subclass dict to make a hashable version.
>>> class hashabledict(dict):
... def __hash__(self):
... return id(self)
...
>>> hd = hashabledict()
>>> d = dict()
>>> d[hd] = "foo"
>>> d
{{}: 'foo'}
>>> hd["hello"] = "world"
>>> d
{{'hello': 'world'}: 'foo'}
This replaces the hash value used for the dict with the object's address in memory.
None of the mutable container types in Python are hashable, because they are mutable and thus their hash value can change over their lifetime.
For maybe the wrong reasons I've ran into this problem a bunch of times; where I want to reference a full dict as a key to something. I don't need it to be mutable, but I do want to preserve and easily access the dict's members.
The easiest way I've found to make the dict immutable and quickly usable as a key value is to make it a JSON (or serialize in your favorite alternative).
For example:
>>> import json
>>> d = {'hey':1, 'there':2}
>>> d_key = json.dumps(d)
>>> d_key
'{"there": 2, "hey": 1}'
>>> d2 = {d_key: 'crazytown'}
>>> d2
{'{"there": 2, "hey": 1}': 'crazytown'}
It's easy to manipulate, since it's just a string. And, it can be de-serialized into an object if you want to reference its members.

Categories