Why dictionaries appear to be reversed? - python

Why dictionaries in python appears reversed?
>>> a = {'one': '1', 'two': '2', 'three': '3', 'four': '4'}
>>> a
{'four': '4', 'three': '3', 'two': '2', 'one': '1'}
How can I fix this?

Dictionaries in python (and hash tables in general) are unordered. In python you can use the sort() method on the keys to sort them.

Dictionaries have no intrinsic order. You'll have to either roll your own ordered dict implementation, use an ordered list of tuples or use an existing ordered dict implementation.

Python3.1 has an OrderedDict
>>> from collections import OrderedDict
>>> o=OrderedDict([('one', '1'), ('two', '2'), ('three', '3'), ('four', '4')])
>>> o
OrderedDict([('one', '1'), ('two', '2'), ('three', '3'), ('four', '4')])
>>> for k,v in o.items():
... print (k,v)
...
one 1
two 2
three 3
four 4

Now you know dicts are unordered, here is how to convert them to a list which you can order
>>> a = {'one': '1', 'two': '2', 'three': '3', 'four': '4'}
>>> a
{'four': '4', 'three': '3', 'two': '2', 'one': '1'}
sorted by key
>>> sorted(a.items())
[('four', '4'), ('one', '1'), ('three', '3'), ('two', '2')]
sorted by value
>>> from operator import itemgetter
>>> sorted(a.items(),key=itemgetter(1))
[('one', '1'), ('two', '2'), ('three', '3'), ('four', '4')]
>>>

And what is the "standard order" you would be expecting? It is very much application dependent. A python dictionary doesn't guarantee key ordering anyways.
In any case, you can iterate over a dictionary keys() the way you want.

From the Python Tutorial:
It is best to think of a dictionary as
an unordered set of key: value pairs
And from the Python Standard Library (about dict.items):
CPython implementation detail: Keys
and values are listed in an arbitrary
order which is non-random, varies
across Python implementations, and
depends on the dictionary’s history of
insertions and deletions.
So if you need to process the dict in a certain order, sort the keys or values, e.g.:
>>> sorted(a.keys())
['four', 'one', 'three', 'two']
>>> sorted(a.values())
['1', '2', '3', '4']

Related

object is not subscriptable with dictionary trying to print dictionary converted using .items

Currently trying to print the first entry of alphabet_numbers.items (a, 1)?
alphabet_numbers = {'a': '1',
'b': '2',
'c': '3',
'd' : '4',
'e': '5'
}
tuple1 = alphabet_numbers.items()
print(tuple1[0,0])
how can print only first entry of tuple1?
If put print(tuple1) I get:
dict_items([('a', '1'), ('b', '2'), ('c', '3'), ('d', '4'), ('e', '5')])
It can be explicitly converted to a list:
alphabet_numbers = {'a': '1',
'b': '2',
'c': '3',
'd': '4',
'e': '5'
}
tuple1 = list(alphabet_numbers.items())
print(tuple1[0][0])
print(list(alphabet_numbers.keys())[0])
Or use function keys, if you are only interested in the first key.
Function items does not return a list, but a view like object.
The type checker mypy reveals the type by using reveal_type(tuple1) of the original example:
typing.ItemsView[builtins.str*, builtins.str*]
first_entry = list(alphabet_numbers.items())[0]
You can print the first entry and it will output a tuple.

Filtering a dictionary based on the first occurence of the value elements

So I have this tricky dictionary of tuples which I want to filter based on the first occurrence of the informative flag in the value elements. If the flag (which is the element occupying the first position of the tuple) is observed in other keys I will only retain only the first key-value pair in which it occurs and subsequent key-value pairs which contain the flag would be skipped.
old_dict = {'abc':[('abc', '1', '5'), ('def', '1', '5'), ('abcd', '2', '5')],
'def':[('abc', '2', '5'), ('def', '1', '5'), ('abcd', '1', '5')],
'ghi':[('ghi', '1', '5'), ('jkl', '1', '4'), ('mno', '2', '4')]}
I have struggled with a lot of attempts and this latest attempt does not produce anything meaningful.
flgset = set()
new_dict = {}
for elem, tp in old_dict.items():
for flg in tp:
flgset.add(flg[0])
counter = 0
for elem, tp in old_dict.items():
for (item1, item2, item3) in tp:
for flg in flgset:
if flg == item1:
counter = 1
new_dict[elem] = [(item1, item2, item3)]
break
Expected results should be:
new_dict = {'abc':[('abc', '1', '5'), ('def', '1', '5'), ('abcd', '2', '5')],
'ghi':[('ghi', '1', '5'), ('jkl', '1', '4'), ('mno', '2', '4')]}
Thanks in advance.
If i get you correctly, the following should do what you want:
flgset = set()
new_dict = {}
for k, tuple_list in old_dict.items():
# if the key is not in flgset, just keep the k, tuple_list pair
if k not in flgset:
new_dict[k] = tuple_list
# update the elements into flgset
# item in this case is ('abc', '2', '5'),
# since you only want to add the first element, use item[0]
for item in tuple_list:
flgset.add(item[0])
Output as such:
new_dict = {'abc': [('abc', '1', '5'), ('def', '1', '5'), ('abcd', '2', '5')],
'ghi': [('ghi', '1', '5'), ('jkl', '1', '4'), ('mno', '2', '4')]}
flgset = {'abc', 'abcd', 'def', 'ghi', 'jkl', 'mno'}
Others may have more efficient ways to do this, but here's one solution that incorporates your intuitions that you need to loop over old_dict items and use a set:
for key, val in old_dict.items():
if val[0][0] not in set([v[0][0] for v in new_dict.values()]):
new_dict.update({key: val})
Here's a brief explanation of what's going on: First, val[0][0] is the "informative flag" from your dictionary entry (i.e. the first item of the first tuple in the entry list). set([v[0][0] for v in new_dict.values()]) will give you the unique values of that flag in your new dictionary. The inner part is a list comprehension to get all the "flags" and then set will give a unique list. The last line just uses the update method to append to it.
REVISED ANSWER
#VinayPai raises two important issues below in the comments. First, this code is inefficient because it reconstructs the test set each time. Here's the more efficient way he suggests:
flag_list = set()
for key, val in old_dict.items():
if val[0][0] not in flag_list:
new_dict.update({key: val})
flag_list.add(val[0][0])
The second issue is that this will produce inconsistent results because dictionaries are not ordered. One possible solution is to use an OrderedDict. But as #SyntaxVoid suggests, this is only necessary if you're using Python3.5 or earlier (here is a great answer discussing the change). If you can create your data in this fashion, it would solve the problem:
from collections import OrderedDict
old_dict = OrderedDict{'abc':[('abc', '1', '5'), ('def', '1', '5'), ('abcd', '2', '5')],
'def':[('abc', '2', '5'), ('def', '1', '5'), ('abcd', '1', '5')],
'ghi':[('ghi', '1', '5'), ('jkl', '1', '4'), ('mno', '2', '4')]}

Python dictionary key assign

I've created a dictionary from a tuple, but can't seem to find an answer as to how I'd switch my keys and values without editing the original tuple. This is what I have so far:
tuples = [('a', '1'), ('b', '1'), ('c', '2'), ('d', '3')]
dic = dict(tuples)
print dic
This gives the output:
{'a': '1', 'b': ''1', 'c': '2', 'd': '3'}
But I'm looking for:
{'1': 'a' 'b', '2': 'c', '3': 'd'}
Is there a simple code that could produce this?
Build a dictionary in a loop, collecting your values into lists:
result = {}
for value, key in tuples:
result.setdefault(key, []).append(value)
The dict.setdefault() method will set and return a default value if the key isn't present. Here I used it to set a default empty list value if the key is not present, so the .append(value) is applied to a list object, always.
Don't try to make this a mix of single string and multi-string list values, you'll only complicate matters down the road.
Demo:
>>> tuples = [('a', '1'), ('b', '1'), ('c', '2'), ('d', '3')]
>>> result = {}
>>> for value, key in tuples:
... result.setdefault(key, []).append(value)
...
>>> result
{'1': ['a', 'b'], '3': ['d'], '2': ['c']}
from operator import itemgetter
from itertools import groupby
first = itemgetter(0)
second = itemgetter(1)
d = dict((x, [v for _, v in y]) for x, y in groupby(sorted(tuples, key=second), key=second)
groupby groups the tuples into a new iterator of tuples, whose first element is the unique second item of each of the original, and whose second element is another iterator consisting of the corresponding first items. A quick example (pretty-printed for clarity):
>>> list(groupby(sorted(tuples, key=second), key=second)))
[('1', <itertools._grouper object at 0x10910b8d0>),
('2', <itertools._grouper object at 0x10910b790>),
('3', <itertools._grouper object at 0x10910b750>)]
The sorting by the same key used by groupby is necessary to ensure all like items are grouped together; groupby only makes one pass through the list.
The subiterators consist of tuples like ('1', 'a'), so the second value in each item is the one we want to add to the value in our new dictionary.

How can I convert a dictionary to a tuple in python?

You may saw this kind of questions a lot, but my demand here is different.
Say I have a dictionary d = {'1': 'stack', '2': 'over', '3': 'flow'}, and I want to make a tuple like t = ('1', 'stack', '2', 'over', '3', 'flow')
What's the simplest way to do it?
You can use itertools.chain. Note that this tuple will not have reproducible order, because dictionaries don't have one:
In [1]: d = {'1': 'stack', '2': 'over', '3': 'flow'}
In [2]: from itertools import chain
In [3]: tuple(chain.from_iterable(d.items()))
Out[3]: ('1', 'stack', '3', 'flow', '2', 'over')
In Python 2.x, you can use d.iteritems() instead of d.items().
Edit: As EdChum notes in the comment, you can ensure the order by applying sorted to the items. Note, however, that by default strings are sorted in lexicographical order:
In [4]: sorted(['2', '10'])
Out[4]: ['10', '2']
You can override this by providing the key parameter to sorted:
In [5]: key = lambda i: (int(i[0]), i[1])
In [6]: tuple(chain.from_iterable(sorted(d.items(), key=key)))
Out[6]: ('1', 'stack', '2', 'over', '3', 'flow')

Updating a python dictionary while adding to existing keys?

I'm looking for the most efficient and pythonic (mainly efficient) way to update a dictionary but keep the old values if an existing key is present. For example...
myDict1 = {'1': ('3', '2'), '3': ('2', '1'), '2': ('3', '1')}
myDict2 = {'4': ('5', '2'), '5': ('2', '4'), '2': ('5', '4')}
myDict1.update(myDict2) gives me the following....
{'1': ('3', '2'), '3': ('2', '1'), '2': ('5', '4'), '5': ('2', '4'), '4': ('5', '2')}
notice how the key '2' exists in both dictionaries and used to have values ('3', '1') but now it has the values from it's key in myDict2 ('5', '4')?
Is there a way to update the dictionary in an efficient manner so as the key '2' ends up having values ('3', '1', '5', '4')? #in no particular order
Thanks in advance
I think the most effective way to do it would be something like this:
for k, v in myDict2.iteritems():
myDict1[k] = myDict1.get(k, ()) + v
But there isn't an update equivalent for what you're looking to do, unfortunately.
What is wrong with 2 in-place update operations?
myDict2.update(myDict1)
myDict1.update(myDict2)
Explanation:
The first update will overwrite the already existing keys with the values from myDict1, and insert all key value pairs in myDict2 which don't exist.
The second update will overwrite the already existing keys in myDict1 with values from myDict2, which are actually the values from myDict1 itself due to the 1st operation. Any new key value pairs inserted will be from the original myDict2.
This of course is conditional to the fact that you don't care about preserving myDict2
Update: With python3, you can do this without having to touch myDict2
myDict1 = {**myDict1, **myDict2, **myDict1}
which would actually be same as
myDict1 = {**myDict2, **myDict1}
Output
{'1': ('3', '2'), '3': ('2', '1'), '2': ('3', '1'), '4': ('5', '2'), '5': ('2', '4')}
The fastest way to merge large dictionaries is to introduce an intermediate object that behaves as though the dicts are merged without actually merging them (see #Raymond Hettinger's answer):
from collections import ChainMap
class MergedMap(ChainMap):
def __getitem__(self, key):
result = []
found = False
for mapping in self.maps:
try:
result.extend(mapping[key])
found = True
except KeyError:
pass
return result if found else self.__missing__(key)
merged = MergedMap(myDict1, myDict2)
Whether it is applicable depends on how you want to use the combined dict later.
It uses collections.ChainMap from Python 3.3+ for convenience to provide the full MutableMapping interface; you could implement only parts that you use on older Python versions.
Perhaps a defaultdict would help
from collections import defaultdict
myDict0= {'1': ('3', '2'), '3': ('2', '1'), '2': ('3', '1')}
myDict2 = {'4': ('5', '2'), '5': ('2', '4'), '2': ('5', '4')}
myDict1 = defaultdict(list)
for (key, value) in myDict0.iteritems():
myDict1[key].extend(value)
for (key, value) in myDict2.iteritems():
myDict1[key].extend(value)
print myDict1
defaultdict(<type 'list'>, {'1': ['3', '2'], '3': ['2', '1'], '2': ['3', '1', '5', '4'], '5': ['2', '4'], '4': ['5', '2']})
No there's no easy way to do it I'm afraid.
The best way is probably iterating and merging. Something like:
for key in myDict1.iterkeys():
# Thank you to user2246674 and Nolen Royalty to help me optimise this in their comments
if key in myDict2:
myDict2[key] = myDict2[key] + myDict1[key]
else:
myDict2[key] = myDict1[key]

Categories

Resources