I am trying to remove a key and value from an OrderedDict but when I use:
dictionary.popitem(key)
it removes the last key and value even when a different key is supplied. Is it possible to remove a key in the middle if the dictionary?
Yes, you can use del:
del dct[key]
Below is a demonstration:
>>> from collections import OrderedDict
>>> dct = OrderedDict()
>>> dct['a'] = 1
>>> dct['b'] = 2
>>> dct['c'] = 3
>>> dct
OrderedDict([('a', 1), ('b', 2), ('c', 3)])
>>> del dct['b']
>>> dct
OrderedDict([('a', 1), ('c', 3)])
>>>
In fact, you should always use del to remove an item from a dictionary. dict.pop and dict.popitem are used to remove an item and return the removed item so that it can be saved for later. If you do not need to save it however, then using these methods is less efficient.
You can use pop, popitem removes the last by default:
d = OrderedDict([(1,2),(3,4)])
d.pop(your_key)
Related
I would like to use a dictionary = {string pair: int}, where the key is a string pair.
My question is how to properly set the keys so that the dictionary knows that ('a', 'b') == ('b', 'a')?
eg. I don't want this: dict = {('a', 'b'):10, ('b', 'a'):12}
but want this dict = {('a', 'b'):22}
I would use frozensets as the keys (they don't depend on order):
>>> d = dict()
>>> d[frozenset(("a", "b"))] = 42
>>> print(d[frozenset(("b", "a"))])
42
Edit: Another option would be to always sort the keys before using them:
>>> d = dict()
>>> d[tuple(sorted(("a", "b")))] = 43
>>> d[tuple(sorted(("b", "a")))]
43
Note that using frozenset(...) will ignore duplicated keys: frozenset(("a", "a", "a")) == frozenset(("a",)), while tuple(sorted(...)) will consider those things different.
You can use defaultdict from collections and add the values.
from collections import defaultdict
li = defaultdict(list)
li[("a", "b")].append(10)
li[("a", "b")].append(12)
for key, value in li.items():
print(key, sum(value))
Output: ("a", "b") 22
how to merge two dictionaries in python 2.7 without changing the order of keys in it. as I have to make a CSV file in the required order. I just want to add B dictionary after A dictionary values.
def Merge(A,B):
m=A.copy()
m.update(B)
return m
I am using this method. I also try with +. but the same result. ** is not working in python 2.7
Dictionaries are unordered containers. So, what you say is not correct. That is, if you simply have two dictionaries, then you have no order.
BUT! You have can order the keys of a dictionary, using the OrderedDict container.
You can consider something like:
>>> from collections import OrderedDict
>>> a = OrderedDict({'a': 1, 'b': 2})
>>> b = OrderedDict({'c': 3, 'd': 4})
>>> c = OrderedDict()
>>>for d in [a, b]:
... for k, v in d.items():
... c.update({k :v})
>>> print(c)
OrderedDict([('a', 1), ('b', 2), ('c', 3), ('d', 4)])
# Or
>>> d = OrderedDict()
>>> d.update(a.copy())
>>> d.update(b.copy())
>>> print(d)
OrderedDict([('a', 1), ('b', 2), ('c', 3), ('d', 4)])
Or, if you want a function:
from collections import OrderedDict
def merge(a, b):
c = OrderedDict()
c.update(a.copy())
c.update(b.copy())
return c
You can read more about OrderedDict here.
Dictionaries are unordered in Python 2. If you need to preserve the order of keys, you'll have to use something else, like a list of pairs, or an OrderedDict. Here's one approach.
from collections import OrderedDict
def merge(a, b):
return OrderedDict((k, v) for d in [a, b] for k, v in d.items())
Dictionaries is considered as an unordered collection of values mapped to certain keys. First, make an ordered dictionary by using OrderedDict from the collections library. Then using the method update() you can create the new dictionary. Here's an example.
# A Python program to demonstrate working of OrderedDict
from collections import OrderedDict
#Form OrderedDicts
dict1 = OrderedDict({"a": 1, "b": 2})
dict2 = OrderedDict({"c": 3, "d": 4})
print "These are two ordered dictionaries:\n"
print dict1 , dict2
#Using update method in python
def Merge(dict1, dict2):
return(dict1.update(dict2))
#Make a duplicate of the first dictionary
dict3 = dict1
#Call function
Merge(dict3, dict2)
print "Combined dictionary:", dict3
If you are just going to make a csv you can create a list of items from both ensuring that the items from one are after the items of the other. Then use the list of tuples to make the csv.
a = {1:1,2:2}
b = {3:3,4:4}
combined = []
combined.extend(a.items())
combined.extend(b.items())
In [8]: combined
Out[8]: [(1, 1), (2, 2), (3, 3), (4, 4)]
I am trying to find out how to reorder my OrderedDict with a list of values.
This is my code:
import collections
dicti = {'a':1, 'b':2, 'c':3}
ordered_dict = collections.OrderedDict(sorted(dicti.items(), key=lambda t: t[0]))
desired_dict_order = [3,2,1]
print 'ordered_dict before reordering =', ordered_dict
for key in desired_dict_order:
ordered_dict[key] = ordered_dict.popitem(key)
print 'ordered_dict after reordering =', ordered_dict
I got this idea from this thread <[please see it] which also answers this question, but I am doing this in Python 2.7 and it doesn’t seem to work, for the output yields this weird result which I do not understand:
ordered_dict before reordering = OrderedDict([('a', 1), ('b', 2), ('c', 3)])
ordered_dict after reordering = OrderedDict([('a', 1), ('b', 2), (1, (2, (3, ('c', 3))))])
What is it doing and how can I achieve it in the right way?
EDIT: I would like to reorder based on the indices of the OrderedDict, so in the end I could reorder the dict even if the dict-keys as well as the dict-values are anything and don't nessecarily enumerate sequentially (like 1, 2, 3)
Look at your code:
desired_dict_order = [3,2,1] # this is a list of numbers - values in your dict, not keys!
print 'ordered_dict before reordering =', ordered_dict
for key in desired_dict_order: # …but here you're using them as keys, which is wrong
ordered_dict[key] = ordered_dict.popitem(key)
Easy way to do the reordering is:
aux_dict = { v: k for k, v in ordered_dict.items() } # reversed dict - keys and values swapped!
ordered_dict = collections.OrderedDict( [ (aux_dict[v], v) for v in desired_dict_order ] )
ordered_dict = collections.OrderedDict(sorted(dicti.items(), key=lambda t: t[1],reverse=True))
Will this produce what you want?
Because you are sorting already on the key, so why not directly sort on the value in reverse?
I am new to Python, and I am familiar with implementations of Multimaps in other languages. Does Python have such a data structure built-in, or available in a commonly-used library?
To illustrate what I mean by "multimap":
a = multidict()
a[1] = 'a'
a[1] = 'b'
a[2] = 'c'
print(a[1]) # prints: ['a', 'b']
print(a[2]) # prints: ['c']
Such a thing is not present in the standard library. You can use a defaultdict though:
>>> from collections import defaultdict
>>> md = defaultdict(list)
>>> md[1].append('a')
>>> md[1].append('b')
>>> md[2].append('c')
>>> md[1]
['a', 'b']
>>> md[2]
['c']
(Instead of list you may want to use set, in which case you'd call .add instead of .append.)
As an aside: look at these two lines you wrote:
a[1] = 'a'
a[1] = 'b'
This seems to indicate that you want the expression a[1] to be equal to two distinct values. This is not possible with dictionaries because their keys are unique and each of them is associated with a single value. What you can do, however, is extract all values inside the list associated with a given key, one by one. You can use iter followed by successive calls to next for that. Or you can just use two loops:
>>> for k, v in md.items():
... for w in v:
... print("md[%d] = '%s'" % (k, w))
...
md[1] = 'a'
md[1] = 'b'
md[2] = 'c'
Just for future visitors. Currently there is a python implementation of Multimap. It's available via pypi
Stephan202 has the right answer, use defaultdict. But if you want something with the interface of C++ STL multimap and much worse performance, you can do this:
multimap = []
multimap.append( (3,'a') )
multimap.append( (2,'x') )
multimap.append( (3,'b') )
multimap.sort()
Now when you iterate through multimap, you'll get pairs like you would in a std::multimap. Unfortunately, that means your loop code will start to look as ugly as C++.
def multimap_iter(multimap,minkey,maxkey=None):
maxkey = minkey if (maxkey is None) else maxkey
for k,v in multimap:
if k<minkey: continue
if k>maxkey: break
yield k,v
# this will print 'a','b'
for k,v in multimap_iter(multimap,3,3):
print v
In summary, defaultdict is really cool and leverages the power of python and you should use it.
You can take list of tuples and than can sort them as if it was a multimap.
listAsMultimap=[]
Let's append some elements (tuples):
listAsMultimap.append((1,'a'))
listAsMultimap.append((2,'c'))
listAsMultimap.append((3,'d'))
listAsMultimap.append((2,'b'))
listAsMultimap.append((5,'e'))
listAsMultimap.append((4,'d'))
Now sort it.
listAsMultimap=sorted(listAsMultimap)
After printing it you will get:
[(1, 'a'), (2, 'b'), (2, 'c'), (3, 'd'), (4, 'd'), (5, 'e')]
That means it is working as a Multimap!
Please note that like multimap here values are also sorted in ascending order if the keys are the same (for key=2, 'b' comes before 'c' although we didn't append them in this order.)
If you want to get them in descending order just change the sorted() function like this:
listAsMultimap=sorted(listAsMultimap,reverse=True)
And after you will get output like this:
[(5, 'e'), (4, 'd'), (3, 'd'), (2, 'c'), (2, 'b'), (1, 'a')]
Similarly here values are in descending order if the keys are the same.
The standard way to write this in Python is with a dict whose elements are each a list or set. As stephan202 says, you can somewhat automate this with a defaultdict, but you don't have to.
In other words I would translate your code to
a = dict()
a[1] = ['a', 'b']
a[2] = ['c']
print(a[1]) # prints: ['a', 'b']
print(a[2]) # prints: ['c']
Or subclass dict:
class Multimap(dict):
def __setitem__(self, key, value):
if key not in self:
dict.__setitem__(self, key, [value]) # call super method to avoid recursion
else
self[key].append(value)
There is no multi-map in the Python standard libs currently.
WebOb has a MultiDict class used to represent HTML form values, and it is used by a few Python Web frameworks, so the implementation is battle tested.
Werkzeug also has a MultiDict class, and for the same reason.
I am using a list to find a max value from a group of items in the list using the line: x=max(dictionary, key=dictionary.get)
This works fine unless two or more values in the dictionary are the same, it just seems to choose one of the max at complete random.
Is there a way that I can get it to print both of the max values, possibly in a list eg:dictionary={'A':2,'B':1,'C':2} which will return x=['A','C']
>>> dictionary = { 'A': 2, 'B': 1, 'C': 2 }
>>> maxValue = max(dictionary.values())
>>> [k for k, v in dictionary.items() if v == maxValue]
['C', 'A']
You can also use a counter to get the items sorted by “most common” (highest value):
>>> from collections import Counter
>>> c = Counter(dictionary)
>>> c.most_common()
[('C', 2), ('A', 2), ('B', 1)]
Unfortunately, the parameter n to most_common gives you n maximum elements, and not all with the maximum value, so you need to filter them manually, e.g. using itertools.takewhile:
>>> from itertools import takewhile
>>> maxValue = c.most_common(1)[0][1]
>>> list(takewhile(lambda x: x[1] == maxValue, c.most_common()))
[('C', 2), ('A', 2)]