Sorting dictionary for printing - python

I want to print a sorted dictionary, which contains a lot of key value pairs (~2000).
Each pair consists of a number as the key and a string as the value.
It is just about printing, i don't want to sort the dictionary actually.
If i use the sorted() method, python sorts my dictionary, but in an awkward way:
{'0':'foo', '1':'bar', '10': 'foofoo', '100': 'foobar', '1000': 'barbar',
'1001': 'barfoo', '1002': 'raboof', ...}
But I want to sort it the 'conventional' way like this:
{'0':'foo', '1':'bar', '2': 'foofoo', '3': 'foobar', '4': 'barbar',
'5': 'barfoo', ... , '1001': 'raboof'}
Can I force the method to behave how I want to, or is there another better solution?

Your keys are strings representing integers; if you want a numeric sort, use int() to turn the keys to integers:
sorted(yourdict, key=int)
gives you a numerically sorted list of keys and
sorted(yourdict.items(), key=lambda i: int(i[0]))
gives you items sorted by the numeric value of the key.
However, if you have sequential keys starting at 0, you should be using a list object instead. Index references are faster than dictionary lookups as there is no hashing step required.
Even if your keys do not start at 0 but are still sequential, for a small start index you'd just pad the list with None values:
[None, 'foo', 'bar', 'foofoo', ...]
and index into that starting at 1.

You cannot sort the dictionary, because they are naturally unordered (they use hashing internally), but you can print the key-value pairs in the sorted way
print sorted(d.items(), key = lambda x: int(x[0]))
Output
[('0', 'foo'),
('1', 'bar'),
('10', 'foofoo'),
('100', 'foobar'),
('1000', 'barbar'),
('1001', 'barfoo'),
('1002', 'raboof')]
If you want to iterate through the dictionary in the sorted manner, by default, then you can use the custom SortedDict class from this answer
Also, you can print the dictionary in sorted way, like this
print "{{{}}}".format(", ".join(["{!r}: {!r}".format(key, d[key]) for key in sorted(d, key=int)]))
# {'0': 'foo', '1': 'bar', '10': 'foofoo', '100': 'foobar', '1000': 'barbar', '1001': 'barfoo', '1002': 'raboof'}

You need not use string as keys. You can use integers:
dct = {0:'foo', 1:'bar', 10: 'foofoo', 2: 'foo2'}
If you need strings then add key argument to sorted(). In your case it will be int for converting string int integer:
sorted(dct, key=int)

Related

Python sort list to set

*edit
I make
word=['I','love','hello','world','love','I']
when I convert to set, It change the order to
print(set(word))
output: {'world', 'I', 'hello', 'love'}
How to sort the set again to be
{'I', 'love', 'hello', 'world'}
Sets are unordered. If you want order, convert back to a list.
E.g.
print(sorted(set(word)))
sorted will sort your items and return a list.
However, if you want to retain the order of your elements rather than sort them, you can use a set for deduplication and a list for ordering, something like this:
def unique(items):
seen = set()
result = []
for item in items:
if item not in seen:
seen.add(item)
result.append(item)
return result
and use it as:
>>> word = ['I','love','hello','world','love','I']
>>> print(unique(word))
['I', 'love', 'hello', 'world']
If you just want an ordered collection of unique values, you can create a dict from the list, either with a dict comprehension or dict.fromkeys. In Python 3, dictionaries will retain insertion order; for older versions, use collections.OrderedDict. The dict will have values besides the keys, but you can just ignore those.
>>> word = ['a','b','c','c','b','e']
>>> {k: None for k in word}
{'a': None, 'b': None, 'c': None, 'e': None}
>>> dict.fromkeys(word)
{'a': None, 'b': None, 'c': None, 'e': None}
Other than sorted, this also works if the original order is different than the sorted order.
>>> word = ['f','a','b','c','c','b','e']
>>> dict.fromkeys(word)
{'f': None, 'a': None, 'b': None, 'c': None, 'e': None}
You can then either convert the result to list or keep it a dict and add more values, but if you make it a set, the order will be lost again. Like a set, the dict also allows fast O(1) lookup, but no set operations like intersection or union.

What is the best way to store the results of str.split() into a dictionary as part of a list comprehension? [duplicate]

This question already has answers here:
How to split a string within a list to create key-value pairs in Python
(5 answers)
Closed 4 years ago.
Given the following sample data:
values=['A 1','B 2','C 3']
I want to create a dictionary where A maps to 1, B to 2, and C to 3. The following works, but there is repetition:
my_dict={value.split()[0]:value.split()[1] for value in values}
The repetition of value.split() looks ugly. Is there a way to more elegantly create the dictionary without repeating value.split()?
Two ways I can think of:
>>> {k:v for k,v in (s.split() for s in values)}
{'A': '1', 'B': '2', 'C': '3'}
>>> dict(s.split() for s in values)
{'A': '1', 'B': '2', 'C': '3'}
I suggesting reading about the dict type: https://docs.python.org/3/library/stdtypes.html#mapping-types-dict; in particular:
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.
as well as the introduction of dict-comprehensions in PEP 274:
The semantics of dict comprehensions can actually be demonstrated in stock Python 2.2, by passing a list comprehension to the built-in dictionary constructor:
>>> dict([(i, chr(65+i)) for i in range(4)])
is semantically equivalent to:
>>> {i : chr(65+i) for i in range(4)}
For a functional solution, you can use dict with map and str.split:
values = ['A 1', 'B 2', 'C 3']
res = dict(map(str.split, values))
{'A': '1', 'B': '2', 'C': '3'}
you can do this way pythonic:
>>> values =['A 1','B 2','C 3']
>>> dict(map(str.split, values))
{'A': '1', 'C': '3', 'B': '2'}
str.split([sep[, maxsplit]])
Return a list of the words in the string, using sep as the delimiter string. If maxsplit is given, at most maxsplit splits are done (thus, the list will have at most maxsplit+1 elements). If maxsplit is not specified or -1, then there is no limit on the number of splits (all possible splits are made).
If sep is given, consecutive delimiters are not grouped together and are deemed to delimit empty strings (for example, '1,,2'.split(',') returns ['1', '', '2']). The sep argument may consist of multiple characters (for example, '1<>2<>3'.split('<>') returns ['1', '2', '3']). Splitting an empty string with a specified separator returns [''].
map(function, iterable, ...)
Apply function to every item of iterable and return a list of the results. If additional iterable arguments are passed, function must take that many arguments and is applied to the items from all iterables in parallel. If one iterable is shorter than another it is assumed to be extended with None items. If function is None, the identity function is assumed; if there are multiple arguments, map() returns a list consisting of tuples containing the corresponding items from all iterables (a kind of transpose operation). The iterable arguments may be a sequence or any iterable object; the result is always a list.
you can see that dictionary is not in ordered as your list. Using collections.orderedDict we can retain the order of the input given.
>>> import collections
>>> values =['A 1','B 2','C 3']
>>> my_ordered_dict = collections.OrderedDict(map(str.split, values))
>>> my_ordered_dict
OrderedDict([('A', '1'), ('B', '2'), ('C', '3')])

In Python, given a dictionary with lists in the values, how do I sort the dictionary based on the amount of items in that list?

I have a dictionary
d={'a': ['apple'], 'd': ['dog', 'dance', 'dragon'], 'r': ['robot'], 'c': ['cow', 'cotton']}
and I want to define a function that will order them by the size of the set. That is, since "d" has 3 items in the value, "c" has 2 items, and "a" and "r" each have one item, I want a dictionary in that order. So
d={'d': ['dog', 'dance', 'dragon'], 'c': ['cow', 'cotton'], 'a': ['apple'], 'r': ['robot']}
What I have so far is
def order_by_set_size(d):
return sorted(d, key=lambda k: len(d[k]), reverse=True)
This gives me a list, but I can't figure out how to have it give me a dictionary. I've looked at a lot of other questions and tried different variations of code and this is as close as I can get.
(I'm using Python 3)
you need to use an OrderedDict
see https://docs.python.org/3/library/collections.html#collections.OrderedDict
Based on their example
from collections import OrderedDict
d={'a': ['apple'], 'd': ['dog', 'dance', 'dragon'], 'r': ['robot'], 'c': ['cow', 'cotton']}
ordered = OrderedDict(sorted(d.items(),key=lambda t: len(t[1]),reverse=True))
Dictionaries are, by definition, unordered key-value pairs. Therefore, the code below is correct, as you can only get a list if you want it to be sorted. In other words, dictionaries cannot be sorted, so the task given is impossible.
def order_by_set_size(d):
return sorted(d, key=lambda k: len(d[k]), reverse=True)

find key value based on value field python dictionary

I have a dictionary where the values are lists. I would like to look for a specific value in the lists (value field of dictionary) and return the key value:
dict={'a':['ab','cd','ef'], 'b':['gh', 'ij'], 'c':['kl', 'mn']}
So for 'ef' I would get 'a', for 'mn' I would get 'c'...
I have tryied
value_key=[a for a,b in dict if value in b]
Any ideas?
Assuming you want to do indexing this way more than once, you should build the reverse mapping, from values (sub-values really) to keys:
{ vsub:k for k, v in d.iteritems() for vsub in v }
This takes your original dict (called d here because dict is a builtin name in Python), and "inverts" it, with the tweak of mapping each sub-value (the elements within the lists).
Once you have this new dict, you can simply index into it by keys like 'ab' to get 'a':
{'ab': 'a', 'ef': 'a', 'mn': 'c', 'kl': 'c', 'ij': 'b', 'cd': 'a', 'gh': 'b'}
Iterate through the dictionary with for key in dict_object, and then use in operator to check if the value being searched is in the dictionary's value corresponding to the key. If it exists, then retain the key for the output.
my_dict,val={"a": ["ab", "cd", "ef"], "b": ["gh", "ij"], "c": ["kl", "mn"]}, "ef"
print [key for key in my_dict if val in my_dict[key]]
# ['a']
The advantage of this method is, it will work irrespective of the current popular Python versions, as we don't have to worry about items and iteritems methods.

Making a dictionary with sets and values

I have the following lists:
keys = ['god', 'hel', 'helo']
values = ['good','god', 'hell', 'hello']
I want to create a dictionary like this:
{'god':set(['god', 'good']), 'hel':'hell', 'helo': 'hello'}
where the key is determined by reducing repeated letters in the value to a single letter.
How would I do this programmatically?
"all repeated letters are reduced to single letters"
Actually according to this rule you don't need the keys list, because it will be created from the values.
Also I would suggest to use a dict of sets for all values, also for the single ones, such as "hell" and "hello". It will make the usage of the dictionary much simpler:
import itertools as it
values = ['good','god', 'hell', 'hello']
d = {}
for value in values:
d.setdefault(''.join(k for k,v in it.groupby(value)), set()).add(value)
# d == {'god': set(['god', 'good']),
# 'hel': set(['hell']),
# 'helo': set(['hello'])}
This should do it for you:
import re
import collections
values = ['good', 'god', 'hell', 'hello']
result = collections.defaultdict(set)
for value in values:
key = re.sub(r'(\w)\1*', r'\1', value)
result[key].add(value)
# result: defaultdict(<type 'set'>, {'hel': set(['hell']), 'god': set(['god', 'good']), 'helo': set(['hello'])})
# if you want to ensure that all your keys exist in the dictionary
keys = ['god', 'hel', 'helo', 'bob']
for key in keys:
result[key]
# result: defaultdict(<type 'set'>, {'hel': set(['hell']), 'god': set(['god', 'good']), 'helo': set(['hello']), 'bob': set([])})
Some code golf (sort of - obviously more obfuscation is possible) upon eumiro's answer, observing that itertools.groupby can be used twice (once to get the letter-sets in order of appearance, something I didn't think of - and again to actually create the key-value pairs for the dictionary).
from itertools import groupby
data = ['good', 'god', 'hell', 'hello']
dict((''.join(k), list(v)) for k, v in groupby(data, lambda x: zip(*groupby(x))[0]))
How it works: each word is first processed with lambda x: zip(*groupby(x))[0]. That is, we take the list of (letter, grouper-object) pairs produced by the groupby generator, transform it into a pair (list-of-letters, list-of-grouper-objects) (the generator contents are implicitly evaluated for passing to zip), and discard the list-of-grouper-objects which we don't want. Then, we group the entire word-list according to the list-of-letters produced by each word, transform the list of letters back into a string, evaluate the grouper-object generators to get the corresponding words, and use those key-value pairs to construct the final dict.
Edit: I guess it's cleaner to do the ''.join step within the lambda:
from itertools import groupby
data = ['good', 'god', 'hell', 'hello']
dict((k, list(v)) for k, v in groupby(data, lambda x: ''.join(zip(*groupby(x))[0])))

Categories