Python: Python:Sort values in dictionary? - python

I have
x = {2:[40,30],3:[24,16],4:[30,2],5:[0,80],6:[19,8]}
and I need to sort dictionary based on the 1st item in the value
so my result should be
{2:[40,30],4:[30,2],3:[24,16],6:[19,8],5:[0,80]}

All you need to do is using dict
d = dict(x)
Since your list is already in the right format to be easily converted to Dictionary, that is, you already have a key-value tuple pair as your list elements.

Simply pass it into dict():
>>> dict([(2, [40, 30]), (4, [30, 2])])
{2: [40, 30], 4: [30, 2]}
Dictionaries don't care what order their values are in:
>>> {'one': 1, 'two': 2} == {'two': 2, 'one': 1}
True
If you want to maintain order, you can use collections.OrderedDict:
>>> from collections import OrderedDict
>>> OrderedDict([(2, [40, 30]), (4, [30, 2])])
OrderedDict([(2, [40, 30]), (4, [30, 2])])

You weren't explicit in your question, but from your comments on other answers you want to preserve the order of the list in dictionary form. A standard dictionary is inherently unordered, however, you can use an OrderedDict instead:
from collections import OrderedDict
x = [(4, [30, 2]), (2, [40, 30])]
d = dict(x)
print(d)
# {2: [40, 30], 4: [30, 2]}
d = OrderedDict(x)
print(d)
# OrderedDict([(4, [30, 2]), (2, [40, 30])])
This preserves the keys in order of addition to the dictionary.

Related

Python: create a sub dictionary swapping the keys

I have a Python dictionary with contains lists such as the following:
my_dict = {
'list1':[10, 20, 30, 40, 50],
'list2':[1, 2, 3, 4, 5, 6, 7],
'list3':[10, 100, 200]
}
I want to create another dictionary, whose keys are the same as the first dictionary, but the values are stored under another key of the dictionary, such as the following:
my_desired_dict = {
'list1':{'my_key':[10, 20, 30, 40, 50]},
'list2':{'my_key':[1, 2, 3, 4, 5, 6, 7]},
'list3':{'my_key':[10, 100, 200]}
}
The key name for the inner dictionary will be the same (my_key) for all. How can I achieve this, thanks for the help.
you can achieve that with a simple dict comprehension
new_key = "aKey"
my_dict = {k: {new_key: v} for k, v in my_dict.items()}
my_desired_dict = {k: {'my_key': v} for k, v in my_dict.items()}

How to get result of Counter into two lists?

I am using Counter from collections to count the occurrence of some numbers. I am trying to put the numbers into one list and the count into another list.
The Counter(array) returns data that likes like {(30: 2, 26: 2, 18: 2)}. I would like for there to be two arrays, say A[] and B[], where A would be [30, 26, 18] and B would be [2, 2, 2].
How would I go about doing this?
You could just zip the items from the dict that Counter returns like,
>>> vals
[26, 26, 18, 18, 30, 30]
>>> import collections
>>> collections.Counter(vals)
Counter({26: 2, 18: 2, 30: 2})
>>> zip(*collections.Counter(vals).items())
[(26, 18, 30), (2, 2, 2)]
>>> a, b = zip(*collections.Counter(vals).items())
>>> a
(26, 18, 30)
>>> b
(2, 2, 2)
Counter is a subclass of dict, so you can use the normal dictionary methods
from collections import Counter
array = [1, 2, 3, 3, 4, 4, 4]
counter = Counter(array)
items = list(counter.keys())
counts = list(counter.values())
isinstance(counter, dict) # True
Use .items() to collect the keys and values:
from collections import Counter
d=['a', 'b', 'b', 'c']
l = Counter(d)
A=[k for k, v in l.items()]
print(A)
Result: ['a', 'b', 'c']
Counter is a spcialized dict. It has keys() and values() as well as items()
from collections import Counter
c =Counter( {30: 2, 26: 2, 18: 77} )
a = list(c.keys()) # make a list from the keys view
b = list(c.values()) # make a list from the values
# or # decompose the list of key,value tuples
A, B = map(list,zip(*c.items()))
print(a,b,A,B,sep="\n")
Output:
[30, 26, 18] # a
[2, 2, 77] # b
[30, 26, 18] # A
[2, 2, 77] # B
Doku:
zip()
map

Sum different lists from dictionaries PYTHON

I have a data structure. A list of 4 dictionaries each with 4 keys and 3 values in a list.
dict_list = [0] {key1: [1, 2, 3]
key2: [4, 5, 6]
key3: [7, 8, 9]
key4: [10, 11, 12]
[1] {key1: [13.......]
key2: [16... etc.
I want to sum each sub column [1, 4, 7, 10]....[2,5,8,11] etc. into the form
new_dict_list = [0] {new_key: [(1+4+7+10), (2,5,8,11), (3,6,9,12)]
[1] {new_key2: [(13+16....) etc.
So I'm basically cascading each column within each dictionary.
I have a VERY explicit and long way to do it so far (checking the math is correct), is there any way to use list comprehensions for something this long-winded or is it not worth the effort in the end?
Use zip to group [1, 4, 7, 10]....[2,5,8,11]:
>>> d = dict_list[0]
>>> zip(*d.values())
[(7, 4, 1, 10), (8, 5, 2, 11), (9, 6, 3, 12)]
Use map to generate the new list:
>>> map(sum, zip(*d.values()))
[22, 26, 30]
If you are using python3.x, you need list(map...) to get the list.
You can use zip and sum function :
dict_lis=[{next(d.iterkeys()):map(sum,zip(*d.values()))} for d in dict_lis]
dict.iterkeys() will returns an iterator of dictionary keys which you can get the first key using next function.but note that it wouldn't return the first key in the order that you have defined your dictionaries.since dictionary items are not ordered you can use collections.OrderedDict to get a ordered dictionary.
Note that you shouldn't have same key in your dictionaries!since you can not use same key in the last combined dictionary!
example :
dict_lis=[{'key1': [1, 2, 3],'key2': [4, 5, 6],'key3': [7, 8, 9],'key4': [10, 11, 12]},{'key5': [13,14,15],'key6': [16,17,18]}]
print [{next(d.iterkeys()):map(sum,zip(*d.values()))} for d in dict_lis]
[{'key3': [22, 26, 30]}, {'key6': [29, 31, 33]}]
Original version using list comprehensions:
# set up the initial data
dict_list = []
dict_list.append({'key1': range(1,4),
'key2': range(4,7),
'key3': range(7,10),
'key4': range(10,13)})
dict_list.append({'key1': range(13,16),
'key2': range(16,19),
'key3': range(19,22),
'key4': range(22,25)})
# generate the new list
new_dict_list = []
for d in dict_list:
new_dict_list.append({'new_key': [sum(v[0] for v in d.values()),
sum(v[1] for v in d.values()),
sum(v[2] for v in d.values())] })
print new_dict_list
The output looks like this:
[{'new_key': [22, 26, 30]}, {'new_key': [70, 74, 78]}]

Identifying lists that have 3 elements in common in a lists of lists

I have a list of lists. If there are subslists that have the first three elements in common , merge them into one list and add all the fourth elements.
The problem is best explained in code and the required output.
a_list = [['apple', 50, 60, 7],
['orange', 70, 50, 8],
['apple', 50, 60, 12]]
# output:
# [['apple', 50, 60, 19], ['orange', 70, 50, 8]]
I already have code for a similar problem (given to me by another user in Stack Overflow some time ago), but i don't understand it completely so I'm unable to modify it accordingly. What this code does is it checks if the 0th and 2nd elements are the same, if they are, it merges the sublists, adding the 1st and 3th element:
import defaultdict
data = [['42x120x1800', 50, '50x90x800', 60],
['42x120x1800', 8, '50x90x800', 10],
['2x10x800', 5, '5x9x80', 6]]
d = defaultdict(lambda :[0, 0])
for sub_list in data:
key = (sub_list[0], sub_list[2])
d[key][0] += sub_list[1]
d[key][1] += sub_list[3]
new_data = [[key[0], val[0], key[1], val[1]] for key, val in d.iteritems()]
# [['2x10x800', 5, '5x9x80', 6], ['42x120x1800', 58, '50x90x800', 70]]
How should the code be modified to fit to my new problem? I'd really appreciate if you could also take the time and explain the code thoroughly, too.
You can use the same principle, by using the first three elements as a key, and using int as the default value factory for the defaultdict (so you get 0 as the initial value):
from collections import defaultdict
a_list = [['apple', 50, 60, 7],
['orange', 70, 50, 8],
['apple', 50, 60, 12]]
d = defaultdict(int)
for sub_list in a_list:
key = tuple(sub_list[:3])
d[key] += sub_list[-1]
new_data = [list(k) + [v] for k, v in d.iteritems()]
If you are using Python 3, you can simplify this to:
d = defaultdict(int)
for *key, v in a_list:
d[tuple(key)] += v
new_data = [list(k) + [v] for k, v in d.items()]
because you can use a starred target to take all 'remaining' values from a list, so each sublist is assigned mostly to key and the last value is assigned to v, making the loop just that little simpler (and there is no .iteritems() method on a dict in Python 3, because .items() is an iterator already).
So, we use a defaultdict that uses 0 as the default value, then for each key generated from the first 3 values (as a tuple so you can use it as a dictionary key) sum the last value.
So for the first item ['apple', 50, 60, 7] we create a key ('apple', 50, 60), look that up in d (where it doesn't exist, but defaultdict will then use int() to create a new value of 0), and add the 7 from that first item.
Do the same for the ('orange', 70, 50) key and value 8.
for the 3rd item we get the ('apple', 50, 60) key again and add 12 to the pre-existing 7 in d[('apple', 50, 60)]. for a total of 19.
Then we turn the (key, value) pairs back into lists and you are done. This results in:
>>> new_data
[['apple', 50, 60, 19], ['orange', 70, 50, 8]]
An alternative implementation that requires sorting the data uses itertools.groupby:
from itertools import groupby
from operator import itemgetter
a_list = [['apple', 50, 60, 7],
['orange', 70, 50, 8],
['apple', 50, 60, 12]]
newlist = [list(key) + [sum(i[-1] for i in sublists)]
for key, sublists in groupby(sorted(a_list), key=itemgetter(0, 1, 2))]
for the same output. This is going to be slower if your data isn't sorted, but it's good to know of different approaches.
I'd do something like this:
>>> a_list = [['apple', 50, 60, 7],
... ['orange', 70, 50, 8],
... ['apple', 50, 60, 12]]
>>>
>>> from collections import defaultdict
>>> d = defaultdict(list)
>>> from operator import itemgetter
>>> getter = itemgetter(0,1,2)
>>> for lst in a_list:
... d[getter(lst)].extend(lst[3:])
...
>>> d
defaultdict(<type 'list'>, {('apple', 50, 60): [7, 12], ('orange', 70, 50): [8]})
>>> print [list(k)+v for k,v in d.items()]
[['apple', 50, 60, 7, 12], ['orange', 70, 50, 8]]
This doesn't give the sum however. It could be easily be fixed by doing:
print [list(k)+[sum(v)] for k,v in d.items()]
There isn't much of a reason to prefer this over the slightly more elegant solution by Martijn, other than it will allow the user to have an input list with more than 4 items (with the latter elements being summed as expected). In other words, this would pass the list:
a_list = [['apple', 50, 60, 7, 12],
['orange', 70, 50, 8]]
as well.
Form the key from [:3] so that you get the first 3 elements.

Create ranked dict with list comprehension

I have a list [5, 90, 23, 12, 34, 89] etc where every two values should be a (ranked) list in the dictionary.
So the list above would become {1: [5, 90], 2: [23, 12], 3: [34, 89]} etc. I've gotten close with list comprehension but haven't cracked it. I tried:
my_list = [5, 90, 23, 12, 34, 89]
my_dict = dict((i+1, [my_list[i], my_list[i+1]]) for i in xrange(0, len(my_list)/2))
Which works for the first key, but all following values are off by one index. How would you do this?
You left a multiple of 2:
dict( (i+1, my_list[2*i : 2*i+2]) for i in xrange(0, len(my_list)/2) )
# ^
BTW, you could do this instead (with Python ≥2.6 or Python ≥3.0):
>>> it = iter(my_list)
>>> dict(enumerate(zip(it, it), start=1))
{1: (5, 90), 2: (23, 12), 3: (34, 89)}
(of course, remember to use itertools.izip instead of zip in Python 2.x)

Categories