Should dict store key in order by inc? - python

I have a dict with integers as keys. Tell me please, does a dict store data with sorted keys or not?
I wrote a little code to test (as follows):
>>>
>>> d = {1: 'a', 3: 'a'}
>>> d
{1: 'a', 3: 'a'}
>>> d[2] = 'a'
>>> d
{1: 'a', 2: 'a', 3: 'a'}
>>>
But I am not sure that this behavior is standard and works all the time.

Dictionaries in python are not sorted. Read more on dicts here:
http://docs.python.org/library/stdtypes.html?highlight=dict#dict
But you can use sorted python built-in method to sort keys:
for k in sorted(myDict):
myDict[k] # do something
Or Look here for collections.OrderedDict implementation
You can also mix sorted method and OrderedDict to use it later(sure this will only word in case you will not add new items into it - otherwise it simply better to use sorted method):
d = {1: 'a', 3: 'a'}
from collections import OrderedDict
sorted_d = OrderedDict((k, d[k]) for k in sorted(d))

A little bit more experimenting would have soon shown you that they are not sorted:
>>> d = {1: 'a', 3: 'a', 8: 'a'}
>>> d
{8: 'a', 1: 'a', 3: 'a'}
but even that is implementation dependant. Don't depend on the order at all.

The internal dict keeps no sorting order for the keys. If you want a fast C-implementation for C python have a look at sorteddict which is included in my ordereddict package for CPython:
http://anthon.home.xs4all.nl/Python/ordereddict/

Related

How to change the order of key-value pairs in a dictionary?

How to move the last key-value pair to the first place?
d = {1 : 'a', 2 : 'b', 3 : 'c'}
Here is what I'm trying to get
d = {3 : 'c', 1 : 'a', 2 : 'b'}
I have no idea how to implement it.
One approach would be:
d = {1: "a", 2: "b", 3: "c"}
print(dict([d.popitem()]) | d)
output
{3: 'c', 1: 'a', 2: 'b'}
popitem() gives a tuple of the last key-value pair in the dictionary. We put it into a list to create an iterable of pair items, then we can call dict() on it.
from documentation:
...Otherwise, the positional argument must be an iterable object. Each
item in the iterable must itself be an iterable with exactly two
objects. The first object of each item becomes a key in the new
dictionary, and the second object the corresponding value.
This works on version 3.9 and above. Since version 3.7, insertion order of the dict is guaranteed to be preserved. Since version 3.9 , dictionaries support union | operator.
It works only if your Python version maintains insertion order (Python 3.7 and later), but you can try:
d = {1 : 'a', 2 : 'b', 3 : 'c'}
# last key
last_k = next(reversed(d))
# put the last key-value pair before the rest
d = {last_k: d.pop(last_k), **d}
d
# {3: 'c', 1: 'a', 2: 'b'}
For a systematic approach, when the dict is "big", you can a mapper which contains a list of old key-new key and then use a dict-comprehension to get a dictionary with the new ordering.
d = {1 : 'a', 2 : 'b', 3 : 'c'}
mapper = [(1, 3), (2, 1), (3, 2)]
new_d = {k_new: d[k_new] for _, k_new in mapper}

How to best reverse a DAG with adjacency list representation?

I have the following DAG adjacency list representation:
# this reads: b depends on a, c depends on a and d depends on b and c
graph = {'b': {'a'}, 'c': {'a'}, 'd': {'b', 'c'}}
I want to get the following inverted representation:
graph = {'a': {'b', 'c'}, 'b': {'d'}, 'c': {'d'}}
Using Python 3.x I can do the following, basically turn the graph into a list of tuples and the convert the list of tuples to a dictionary (collapsing different values into a set):
inverted_graph = {}
for k, v in [(v, k) for k in graph for v in graph[k]]:
inverted_graph.setdefault(k, set()).add(v)
Is there a simpler / faster way to do it without double looping?
I'm not sure why you wrote this triple loop. Two loops should be sufficient. You don't need an extra loop to swap k and v when you can just use them in opposite places.
Also, a defaultdict can simplify the code.
from collections import defaultdict
inverted_graph = defaultdict(set)
for k in graph:
for v in graph[k]:
inverted_graph[v].add(k)

Dictionary Comprehension in Python for key:[1,2,3] [duplicate]

This question already has answers here:
is it possible to reverse a dictionary in python using dictionary comprehension
(5 answers)
Closed 2 years ago.
While I've been improving my Python skills I have one question.
My code is below:
# def invertDictionary(dict):
# new_dict = {}
# for key, value in dict.items():
# if value in new_dict:
# new_dict[value].append(key)
# else:
# new_dict[value]=[key]
# return new_dict
def invertDictionary(dict):
new_dict = {value:([key] if value else [key]) for key, value in dict.items()}
return new_dict;
invertDictionary({'a':3, 'b':3, 'c':3})
I am trying to get output like {3:['a','b','c']}. I have achieved that using a normal for-loop; I just want to know how to get these results using a Dictionary Comprehension. I tried but in append it's getting an error. Please let me know how to achieve this.
Thanks in Advance!
You missed that you also need a list comprehension to build the list.
Iterate over the values in the dict, and build the needed list of keys for each one.
Note that this is a quadratic process, whereas the canonical (and more readable) for loop is linear.
d = {'a':3, 'b':3, 'c':3, 'e':4, 'f':4, 'g':0}
inv_dict = {v: [key for key, val in d.items() if val == v]
for v in set(d.values())}
result:
{0: ['g'],
3: ['a', 'b', 'c'],
4: ['e', 'f']
}
Will this do?
while your original version with a regular for loop is the best solution for this, here is a variation on #Prune answer that doesn't goes over the dict multiple times
>>> import itertools
>>> d = {'a':3, 'b':3, 'c':3, 'e':4, 'f':4, 'g':0}
>>> {group_key:[k for k,_ in dict_items]
for group_key,dict_items in itertools.groupby(
sorted(d.items(),key=lambda x:x[-1]),
key=lambda x:x[-1]
)
}
{0: ['g'], 3: ['a', 'b', 'c'], 4: ['e', 'f']}
>>>
first we sorted the items of the dict by value with a key function to sorted using a lambda function to extract the value part of the item tuple, then we use the groupby to group those with the same value together with the same key function and finally with a list comprehension extract just the key
--
as noted by Kelly, we can use the get method from the dict to get the value to make it shorter and use the fact that iteration over a dict give you its keys
>>> {k: list(g) for k, g in itertools.groupby(sorted(d, key=d.get), d.get)}
{0: ['g'], 3: ['a', 'b', 'c'], 4: ['e', 'f']}
>>>
You could use a defalutdict and the append method.
from collections import defaultdict
dict1 = {'a': 3, 'b': 3, 'c': 3}
dict2 = defaultdict(list)
{dict2[v].append(k) for k, v in dict1.items()}
dict2
>>> defaultdict(list, {3: ['a', 'b', 'c']})

Group list of dictionaries by value [duplicate]

This question already has answers here:
Grouping Python dictionary keys as a list and create a new dictionary with this list as a value
(2 answers)
Closed 4 years ago.
I have a list of dictionaries. How can i group that list by valaues.
list = [{a:1},{b:2},{c:1},{d:3},{e:2}]
Now my result should be like below
1:a,c
2:b,e
3:d
I tried using groupby from itertools. But i couldn't get the required result. I am using python 2.7.
Could you help me achieve this?
If you want to use groupby, the list has to be sorted by the same key you want to group by.
>>> lst = [{'a':1}, {'b':2}, {'c':1}, {'d':3}, {'e':2}]
>>> keyfunc = lambda d: next(iter(d.values()))
>>> sorted(lst, key=keyfunc)
[{'a': 1}, {'c': 1}, {'b': 2}, {'e': 2}, {'d': 3}]
>>> {k: [x for d in g for x in d]
... for k, g in itertools.groupby(sorted(lst, key=keyfunc), key=keyfunc)}
{1: ['a', 'c'], 2: ['b', 'e'], 3: ['d']}
Here's a possible solution without using any library.
def get_dict(list):
res = {}
for elem in list:
k, v = elem.keys(), elem.values()
if v[0] in res:
res[v[0]].append(k[0])
else:
res[v[0]] = [k[0]]
return res
With a list like yours, this would output a dictionary with the following format:
{ 1:[a,c], 2:[b, e], 3:[c] }
This is considering you're always going to have the same format as input. If not, you could just adjust what is read and saved.
This might help.
list = [{"a":1},{"b":2},{"c":1},{"d":3},{"e":2}]
d = {}
for i in list:
key, value = i.items()[0]
if value not in d:
d[value] = [key]
else:
d[value].append(key)
print(d)
Output:
{1: ['a', 'c'], 2: ['b', 'e'], 3: ['d']}
Tested in python2.7
Here is a way to do what you are looking for:
list_ = [{"a":1},{"b":2},{"c":1},{"d":3},{"e":2}]
values = set(value for dic in list_ for value in dic.values())
for value in values:
keys = [list(dic.keys())[0] for dic in list_ if value in dic.values()]
print("{}: {}".format(value, keys))
Output:
1: ['a', 'c']
2: ['b', 'e']
3: ['d']
Here's a solution that uses defaultdict.
from __future__ import print_function
from collections import defaultdict
lst = [{'a': 1}, {'b': 2}, {'c': 1}, {'d': 3}, {'e': 2}]
d = defaultdict(list)
for l in lst:
val, key = l.items()[0]
d[key].append(val)
print(d)
Output:
defaultdict(<type 'list'>, {1: ['a', 'c'], 2: ['b', 'e'], 3: ['d']})

How to add new values to key in a dict?

If I had a sample dict:
mydict = {1:{2:'A'}}
how can I add new data to key 1 so that it can be like:
mydict = {1:{2:'A'},{3:'B'}}
When I do mydict.update({3:'B'})
I get:
{1: {2: 'A'}, 3: 'B'} not {1: {2: 'A'}, {3: 'B'}}
If I try .update using the same key it just replaces the data:
mydict.update({1:{3:'B'}}) becomes
{1: {3: 'B'}}
There already have a good library for you:
from collections import defaultdict
d = defaultdict(dict)
d['person']['name']='frank'
d['person']['age']='age'
and then you can easily get the data from your 2 key! like:
print d['person']['name']
When you do mydict.update({3:'B'}) you are updating the wrong dictionary.
It looks like you want to update the dictionary in mydict[1]
This is assuming you actually want a result of {1: {2: 'A', 3: 'B'}} as your example {1: {2: 'A'}, {3: 'B'}} is not valid python.
So try mydict[1].update({3:'B'})
Simply add
mydict[1].update({3:'B'})
mydict ={2:'a',3:'b'}
d={1:mydict}
print (d)
{1: {2: 'a', 3: 'b'}}
to update more key:values you can add to mydict

Categories