sorting nested tuple list - python

So, what I am trying to do, is to sort a list with that contains (num, tuple) I want to sort it first by the second value of the tuple and if 2 are equal, I want to sort it by the num(of the first tuple).
So lets say I have:
l = [(1,(2,3)),(3,(2,1)),(2,(2,1))]
print(l.sort(key=something))
[(2,(2,1)), (3,(2,1)), (1,(2,3))]
I have tried:
l.sort(key=itemgetter(1,0)
Of course it didn't work. Any ideas?
Thank you.

operator.itemgetter works fine:
>>> from operator import itemgetter
>>> l = [(1,(2,3)),(3,(2,1)),(2,(2,1))]
>>> l.sort(key=itemgetter(1,0))
>>> print(l)
[(2, (2, 1)), (3, (2, 1)), (1, (2, 3))]
>>>
I think the problem is that you tried to print the result of list.sort. You cannot do this because it is an in-place method (it always returns None).

>>> l = [(1,(2,3)),(3,(2,1)),(2,(2,1))]
>>> sorted(l, key=lambda t: (t[1][1],t[0]))
[(2, (2, 1)), (3, (2, 1)), (1, (2, 3))]
Or:
>>> from operator import itemgetter
>>> sorted(l, key=itemgetter(1,0))
[(2, (2, 1)), (3, (2, 1)), (1, (2, 3))]

this works too:
l.sort(key=lambda x: x[::-1])
Note that list.sort sorts the list in place, so print(l.sort(key=something)) would print None.

Related

Difficulty Sorting Tuples with itemgetter

I'm new to Python as the screen name attests. I was attempting to sort a list of tuples, think (x,y) pairs in a list and ran into a problem. My goal is to sort the list of tuples by the x variables in ascending order primarily but then sort
I investigated the wiki on HowToSort at http://wiki.python.org/moin/HowTo/Sorting/ and thought I would try the operator module and the itemgetter function as a key.
The simple sorted() function can sort the tuple fine, but when you want one index ascending and one ascending, I'm lost. Here is the code:
from operator import itemgetter, attrgetter
ItemList = [(1,7),(2,1),(1,5),(1,1)]
# Want list sorted with X values descending, then y values ascending
# expected [(2, 1), (1, 1), (1,5), (1, 7)]
print
print ' Input:', ItemList
print 'Output1:',sorted(ItemList, reverse = True)
print
print ' Input:', ItemList
print 'Output2:', sorted(ItemList, key = itemgetter(-0,1))
print
print ' WANTED:', '[(2, 1), (1, 1), (1,5), (1, 7)]'
with the following output:
Input: [(1, 7), (2, 1), (1, 5), (1, 1)]
Output1: [(2, 1), (1, 7), (1, 5), (1, 1)]
Input: [(1, 7), (2, 1), (1, 5), (1, 1)]
Output2: [(1, 1), (1, 5), (1, 7), (2, 1)]
WANTED: [(2, 1), (1, 1), (1, 5), (1, 7)]
I obviously, do not understand the itemgetter function, so any help would be appreciated on that.
Also, any ideas on how to do the two sort on (x,y) pairs? I am hoping to avoid a lambda solution but I'm sure that's where this is going. Thanks.
-0 is the same thing as 0. More-over, negative indices have a different meaning to itemgetter(); it does not mean that the values are negated.
Use a lambda instead:
sorted(ItemList, key=lambda item: (-item[0], item[1]))
Demo:
>>> ItemList = [(1,7),(2,1),(1,5),(1,1)]
>>> sorted(ItemList, key=lambda item: (-item[0], item[1]))
[(2, 1), (1, 1), (1, 5), (1, 7)]
Negative indices take items from the end of a sequence:
>>> end = itemgetter(-1)
>>> end([1, 2, 3])
3
The itemgetter() will never modify the retrieved item, certainly not negate it.
Note that itemgetter() is only a convenience method, you do not have to use it and for more complex sorting orders, a custom function or lambda is the better choice.

Python Easiest Way to Sum List Intersection of List of Tuples

Let's say I have the following two lists of tuples
myList = [(1, 7), (3, 3), (5, 9)]
otherList = [(2, 4), (3, 5), (5, 2), (7, 8)]
returns => [(1, 7), (2, 4), (3, 8), (5, 11), (7, 8)]
I would like to design a merge operation that merges these two lists by checking for any intersections on the first element of the tuple, if there are intersections, add the second elements of each tuple in question (merge the two). After the operation I would like to sort based upon the first element.
I am also posting this because I think its a pretty common problem that has an obvious solution, but I feel that there could be very pythonic solutions to this question ;)
Use a dictionary for the result:
result = {}
for k, v in my_list + other_list:
result[k] = result.get(k, 0) + v
If you want a list of tuples, you can get it via result.items(). The resulting list will be in arbitrary order, but of course you can sort it if desired.
(Note that I renamed your lists to conform with Python's style conventions.)
Use defaultdict:
from collections import defaultdict
results_dict = defaultdict(int)
results_dict.update(my_list)
for a, b in other_list:
results_dict[a] += b
results = sorted(results_dict.items())
Note: When sorting sequences, sorted sorts by the first item in the sequence. If the first elements are the same, then it compares the second element. You can give sorted a function to sort by, using the key keyword argument:
results = sorted(results_dict.items(), key=lambda x: x[1]) #sort by the 2nd item
or
results = sorted(results_dict.items(), key=lambda x: abs(x[0])) #sort by absolute value
A method using itertools:
>>> myList = [(1, 7), (3, 3), (5, 9)]
>>> otherList = [(2, 4), (3, 5), (5, 2), (7, 8)]
>>> import itertools
>>> merged = []
>>> for k, g in itertools.groupby(sorted(myList + otherList), lambda e: e[0]):
... merged.append((k, sum(e[1] for e in g)))
...
>>> merged
[(1, 7), (2, 4), (3, 8), (5, 11), (7, 8)]
This first concatenates the two lists together and sorts it. itertools.groupby returns the elements of the merged list, grouped by the first element of the tuple, so it just sums them up and places it into the merged list.
>>> [(k, sum(v for x,v in myList + otherList if k == x)) for k in dict(myList + otherList).keys()]
[(1, 7), (2, 4), (3, 8), (5, 11), (7, 8)]
>>>
tested for both Python2.7 and 3.2
dict(myList + otherList).keys() returns an iterable containing a set of the keys for the joined lists
sum(...) takes 'k' to loop again through the joined list and add up tuple items 'v' where k == x
... but the extra looping adds processing overhead. Using an explicit dictionary as proposed by Sven Marnach avoids it.

Delete (a,b) from a python list of tuples if (b,a) exists

From a python list of tuples (which is essentially a cartesian product of a list with itself) I want to delete (a,b) if (b,a) is in the list.Only one of (a,b) or (b,a) must be retained. So a list
[(1,1),(1,2),(1,3),(2,1),(2,2),(2,3),(3,1),(3,2),(3,3)]
must reduce to
[(1,2),(1,3),(2,3)]
(Although deleting (1,2) and retaining (2,1) is fine)
I tried doing this but I am not sure about deleting from a list while iterating over it. This doesn't work. (Gives me [(1, 2), (2, 1), (2, 3), (3, 1), (3, 3)])
[pairs.remove((a,b)) for (a,b) in pairs if ((b,a) in pairs)]
Why delete the incorrect ones from the list?
Use itertools.combinations to generate the correct ones instead.
>>> import itertools
>>> list(itertools.combinations((1, 2, 3), 2))
[(1, 2), (1, 3), (2, 3)]
>>> [el for el in pairs if el[0] < el[1]]
[(1,2),(1,3),(2,3)]
pairs = [(1,1),(1,2),(1,3),(2,1),(2,2),(2,3),(3,1),(3,2),(3,3)]
new_pairs = []
for a, b in pairs:
if (a, b) in new_pairs or (b, a) in new_pairs:
pass
else:
new_pairs += [(a,b)]
new_pairs = [(1, 1), (1, 2), (1, 3), (2, 2), (2, 3), (3, 3)]

python count items in list and keep their order of occurrance

Given: a list, such as l=[4,4,4,4,5,5,5,6,7,7,7]
Todo: get the count of an element and keep their occurrence order, e.g.:
[(4,4),(5,3),(6,1),(7,3)]
I could do it with:
tmpL = [(i,l.count(i)) for i in l]
tmpS = set()
cntList = [x for x in tmpL if x not in tmpS and not tmpS.add(x)]
But is there a better way? I have seen the link here, but it sorts the counts and hence breaks the order.
Edit: performance is not an issue for the solution, preferable something built-in.
Use groupby:
>>> l = [4,4,4,4,5,5,5,6,7,7,7,2,2]
>>> from itertools import groupby
>>> [(i, l.count(i)) for i,_ in groupby(l)]
[(4, 4), (5, 3), (6, 1), (7, 3), (2, 2)]
>>> import itertools
>>> [(k, len(list(g))) for k, g in itertools.groupby(l)]
[(4, 4), (5, 3), (6, 1), (7, 3)]
This keeps the order of the items and also allows repeated items:
>>> l=[4,4,4,4,5,5,5,6,7,7,7,4,4,4,4,4]
>>> [(k, len(list(g))) for k, g in itertools.groupby(l)]
[(4, 4), (5, 3), (6, 1), (7, 3), (4, 5)]
If you are using Python 2.7, you can use the Counter from collections, which does exactly what you are looking to do:
http://docs.python.org/library/collections.html#collections.Counter

Python - convert list of tuples to string

Which is the most pythonic way to convert a list of tuples to string?
I have:
[(1,2), (3,4)]
and I want:
"(1,2), (3,4)"
My solution to this has been:
l=[(1,2),(3,4)]
s=""
for t in l:
s += "(%s,%s)," % t
s = s[:-1]
Is there a more pythonic way to do this?
You can try something like this (see also on ideone.com):
myList = [(1,2),(3,4)]
print ",".join("(%s,%s)" % tup for tup in myList)
# (1,2),(3,4)
you might want to use something such simple as:
>>> l = [(1,2), (3,4)]
>>> str(l).strip('[]')
'(1, 2), (3, 4)'
.. which is handy, but not guaranteed to work correctly
How about:
>>> tups = [(1, 2), (3, 4)]
>>> ', '.join(map(str, tups))
'(1, 2), (3, 4)'
The most pythonic solution is
tuples = [(1, 2), (3, 4)]
tuple_strings = ['(%s, %s)' % tuple for tuple in tuples]
result = ', '.join(tuple_strings)
How about
l = [(1, 2), (3, 4)]
print repr(l)[1:-1]
# (1, 2), (3, 4)
I think this is pretty neat:
>>> l = [(1,2), (3,4)]
>>> "".join(str(l)).strip('[]')
'(1,2), (3,4)'
Try it, it worked like a charm for me.
Three more :)
l = [(1,2), (3,4)]
unicode(l)[1:-1]
# u'(1, 2), (3, 4)'
("%s, "*len(l) % tuple(l))[:-2]
# '(1, 2), (3, 4)'
", ".join(["%s"]*len(l)) % tuple(l)
# '(1, 2), (3, 4)'

Categories

Resources