Sum values in tuple (values in dict) - python

I have a dictionary data that looks like that with sample values:
defaultdict(<type 'list'>,
{(None, 2014): [(5, 1), (10, 2)],
(u'Middle', 2014): [(6, 2), (11, 3)],
(u'SouthWest', 2015): [(7,3), (12, 4)]})
I get this from collections.defaultdict(list) because my keys have to be lists.
My goal is to get a new dictionary that will contain the sum values for every tuple with respect to their position in the tuple.
By running
out = {k:(sum(tup[0] for tup in v),sum(tup[1] for tup in v)) for k,v in data.items()}
I get
{(None, 2014): (15, 3), (u'Middle', 2014): (17, 5), (u'SouthWest', 2015): (19, 7)}
However, I don't know in advance how many items will be in every tuple, so using the sum(tup[0] for tup in v) with hard-coded indices is not an option. I know, however, how many integers will be in the tuple. This value is an integer and I get this along with the data dict. All tuples are always of the same length (in this example, of length 2).
How do I tell Python that I want the out dict to contain tuple of the size that matches the length I have to use?

I think you want the built-in zip function:
In [26]: {k: tuple(sum(x) for x in zip(*v)) for k, v in data.items()}
Out[26]:
{('SouthWest', 2015): (19, 7),
(None, 2014): (15, 3),
('Middle', 2014): (17, 5)}

Related

How to filter dictionary by value? [duplicate]

This question already has answers here:
How to filter a dictionary according to an arbitrary condition function?
(7 answers)
Closed 4 years ago.
I have dictionary in format "site_mame": (side_id, frequency):
d=[{'fpdownload2.macromedia.com': (1, 88),
'laposte.net': (2, 23),
'www.laposte.net': (3, 119),
'www.google.com': (4, 5441),
'match.rtbidder.net': (5, 84),
'x2.vindicosuite.com': (6, 37),
'rp.gwallet.com': (7, 88)}]
Is there a smart way to filter dictionary d by value so that I have only those positions, where frequency is less than 100? For example:
d=[{'fpdownload2.macromedia.com': (1, 88),
'laposte.net': (2, 23),
'match.rtbidder.net': (5, 84),
'x2.vindicosuite.com': (6, 37),
'rp.gwallet.com': (7, 88)}]
I don't want to use loops, just looking for smart and efficient solution...
You can use a dictionary comprehension with unpacking for a more Pythonic result:
d=[{'fpdownload2.macromedia.com': (1, 88),
'laposte.net': (2, 23),
'www.laposte.net': (3, 119),
'www.google.com': (4, 5441),
'match.rtbidder.net': (5, 84),
'x2.vindicosuite.com': (6, 37),
'rp.gwallet.com': (7, 88)}]
new_data = [{a:(b, c) for a, (b, c) in d[0].items() if c < 100}]
Output:
[{'laposte.net': (2, 23), 'fpdownload2.macromedia.com': (1, 88), 'match.rtbidder.net': (5, 84), 'x2.vindicosuite.com': (6, 37), 'rp.gwallet.com': (7, 88)}]
You can use a dictionary comprehension to do the filtering:
d = {
'fpdownload2.macromedia.com': (1, 88),
'laposte.net': (2, 23),
'www.laposte.net': (3, 119),
'www.google.com': (4, 5441),
'match.rtbidder.net': (5, 84),
'x2.vindicosuite.com': (6, 37),
'rp.gwallet.com': (7, 88),
}
d_filtered = {
k: v
for k, v in d.items()
if v[1] < 100
}
What you want is a dictionary comprehension. I'll show it with a different example:
d = {'spam': 120, 'eggs': 20, 'ham': 37, 'cheese': 101}
d = {key: value for key, value in d.items() if value >= 100}
If you don't already understand list comprehensions, this probably looks like magic that you won't be able to maintain and debug, so I'll show you how to break it out into an explicit loop statement that you should be able to understand easily:
new_d = {}
for key, value in d.items():
if value >= 100:
new_d[key] = value
If you can't figure out how to turn that back into the comprehension, just use the statement version until you learn a bit more; it's a bit more verbose, but better to have code you can think through in your head.
Your problem is slightly more complicated, because the values aren't just a number but a tuple of two numbers (so you want to filter on value[1], not value). And because you have a list of one dict rather than just a dict (so you may need to do this for each dict in the list). And of course my filter test isn't the same as yours. But hopefully you can figure it out from here.

Storing python list of tuples in a redis sorted set where second element of tuple is used as score

I have a Python list of tuples like so:
lst = [(22, -150.0), (23, -150.0), (18, -148.5), (15, -99.4), (5, -75.75), (4, -49.2), (13, -49.0), (9, -41.3), (20, -25.5), (17, -22.3), (10, -13.1), (16, -12.5), (14, -9.8), (3, -8.5), (1, -8.4), (12, -1.5), (7, -0.6), (2, -0.4), (6, 1.7), (21, 2.7)]
How do I pass that into a redis sorted set, such that the second value in each tuple is used as the score? I tried zadd(sorted_set, *lst), but I'm getting the error value is not a valid float.
The zadd method of redis.StrictRedis expects arguments in the form of
zadd(key, score1, name1, score2, name2, ...)
In other words, you need to reverse and unpack the inner tuples as well:
In [6]: r = redis.StrictRedis(...)
In [8]: r.zadd('sset', *(y for x in lst for y in x[::-1]))
Out[8]: 20
Redis.zadd and StrictRedis.zadd behave differently -- see README for more details. So if you use redis.Redis instead of redis.StrictRedis (you shouldn't), do not reverse tuples:
r.zadd('sset', *(y for x in lst for y in x))

Python Remove two for loop and solve using some iterator tool

I have a dictionary
input = {
1:[23,24],
2:[21],
3:[23],
4:[]
}
I want output like this:-
output = (1,23),(1,24),(2,21),(3,23)
I did this using two for loop:-
>>> for key in input:
... for value in input[key]:
... print """(""" + str(key) + """,""" +str(value) + """)"""
...
(1,23)
(1,24)
(2,21)
(3,23)
can somebody tell me another approach ? Using some iterator tool or any other way?
Thanks
>>> [(key, value) for key, values in input.items() for value in values]
>>> [(1, 23), (1, 24), (2, 21), (3, 23)]
>>> '\n'.join('({},{})'.format(key, value) for key, values in input.items() for value in values)
'(1,23)\n(1, 24)\n(2, 21)\n(3, 23)'
>>> print('\n'.join('({},{})'.format(key, value) for key, values in input.items() for value in values))
(1,23)
(1,24)
(2,21)
(3,23)
>>> ','.join('({},{})'.format(key, value) for key, values in input.items() for value in values)
'(1,23),(1,24),(2,21),(3,23)'
Nice Question. Here is some pythonic solution. Expect some more pythonic solutions to come.
input = {
1:[23,24],
2:[21],
3:[23],
4:[]
}
def get_tuple(key,list):
def map_key_value(element):
return (key,element)
return map(map_key_value,list)
def list_extend(elem1, elem2):
elem1.extend(elem2)
return elem1
print reduce(list_extend,map(get_tuple, input.keys(), input.values()))
>>> [(1, 23), (1, 24), (2, 21), (3, 23)]
Here is the short explanation:
map(get_tuple, input.keys(), input.values()) will return us the
>>> [[(1, 23), (1, 24)], [(2, 21)], [(3, 23)], []]
Basically we will get the list of lists. We then pass this list of lists to reduce, which gives us the single list, combining all into one.
Hence, we will get -
>>> [(1, 23), (1, 24), (2, 21), (3, 23)].

Sort dict of tuples by either tuple value with customised comparator

I'm working on some python dicts of tuples. Each tuple containing 2 ints. The first digit in the tuple is reffered to as value and the second digit is referred to as work. I have 3 different comparators and I need to sort the dicts into descending order. This order should be determined by which comparator is called. i.e. the dict can be sorted 3 different ways. I've tried as many different ways as I could find to get this to work. I can do it without using the comparator by just breaking it up into a list and sorting by slicing the tuples but if anyone can shed some light on the syntax to sort using the comparators it would be greatly appreciated. Mine seems to be returning correctly for cmpWork but the other 2 aren't reversed.
Also it would be great if I could get the dict sorted by the tuple values.
I got a sort working with
sortedSubjects = sorted(tmpSubjects.iteritems(), key = operator.itemgetter(1), reverse = True)
but this doesn't let me slice the tuples.
First time posting noob so apologies for any mistakes.
def cmpValue(subInfo1, subInfo2):
return cmp(subInfo2[0] , subInfo1[0])
def cmpWork(subInfo1, subInfo2):
return cmp(subInfo1[1] , subInfo2[1])
def cmpRatio(subInfo1, subInfo2):
return cmp((float(subInfo2[0]) / subInfo2[1]) , (float(subInfo1[0]) / subInfo1[1]))
def greedyAdvisor(subjects, comparator):
tmpSubjects = subjects.copy()
sortedSubjects = sorted(tmpSubjects.values(), comparator, reverse = True)
print sortedSubjects
smallCatalog = {'6.00': (16, 8),'1.00': (7, 7),'6.01': (5, 3),'15.01': (9, 6)}
greedyAdvisor(smallCatalog, cmpRatio)
greedyAdvisor(smallCatalog, cmpValue)
greedyAdvisor(smallCatalog, cmpWork)
[(7, 7), (9, 6), (5, 3), (16, 8)]
[(5, 3), (7, 7), (9, 6), (16, 8)]
[(16, 8), (7, 7), (9, 6), (5, 3)]
ps
The line
sortedSubjects = sorted(tmpSubjects.iteritems(), key = operator.itemgetter(1), reverse = True)
returns
[('6.00', (16, 8)), ('15.01', (9, 6)), ('1.00', (7, 7)), ('6.01', (5, 3))]
which is almost exactly what I'm looking for except that I can't sort by the second value in the tuple and I can't sort by cmpRatio either.
but this doesn't let me slice the tuples
Starting with your example:
sortedSubjects = sorted(tmpSubjects.iteritems(),
key=operator.itemgetter(1),
cmp=comparator, # What about specifying the comparison?
reverse=True)
If you need to sort dictionary - use collections.OrderedDict
E.g., sort by 1st element of tuple
OrderedDict(sorted(smallCatalog.items(), key=lambda e:e[1][0]))
Out[109]: OrderedDict([('6.01', (5, 3)), ('1.00', (7, 7)), ('15.01', (9, 6)), ('6.00', (16, 8))])

Making list of list oneliner -python

I have a list
l=[(1,2),(1,6),(3,4),(3,6),(1,4),(4,3)]
I want to return a list that contains lists by the first number in each tuple.
Something like this:
[[2,4,6],[4,6],[3]]
To make a program that iterates on list and writing a whole function that does it is easy.
I want to find a oneliner - python way of doing it.
Any ideas?
>>> from itertools import groupby
>>> from operator import itemgetter
>>> L = [(1,2), (1,6), (3,4), (3,6), (1,4), (4,3)]
>>> [[y for x, y in v] for k, v in groupby(sorted(L), itemgetter(0))]
[[2, 4, 6], [4, 6], [3]]
Explanation
This works by using itertools.groupby. groupby finds consecutive groups in an iterable, returning an iterator through key, group pairs.
The argument given to groupby is a key function, itemgetter(0) which is called for each tuple, returning the first item as the key to groupby.
groupby groups elements in their original order so if you want to group by the first number in the list, it must first be sorted so groupby can go through the first numbers in ascending order and actually group them.
>>> sorted(L)
[(1, 2), (1, 4), (1, 6), (3, 4), (3, 6), (4, 3)]
There is the sorted list where you can clearly see the groups that will be created if you look back to the final output. Now you can use groupby to show the key, group pairs.
[(1, <itertools._grouper object at 0x02BB7ED0>), (3, <itertools._grouper object at 0x02BB7CF0>), (4, <itertools._grouper object at 0x02BB7E30>)]
Here are the sorted items grouped by the first number. groupby returns the group for each key as an iterator, this is great and very efficient but for this example we will just convert it to a list to make sure it's working properly.
>>> [(k, list(v)) for k,v in groupby(sorted(L), itemgetter(0))]
[(1, [(1, 2), (1, 4), (1, 6)]), (3, [(3, 4), (3, 6)]), (4, [(4, 3)])]
That is almost the right thing but the required output shows only the 2nd number in the groups in each list. So the following achieves the desired result.
[[y for x, y in v] for k, v in groupby(sorted(L), itemgetter(0))]
l = [(1, 2), (1, 6), (3, 4), (3, 6), (1, 4), (4, 3)]
d = {}
for (k, v) in l:
d.setdefault(k, []).append(v)
print d.values()
I know it's not a one liner, but perhaps it's easier to read than a one liner.

Categories