I'm trying to compare things in list, tuple, etc. and I'm wondering how we specify what we want to compare. I want to sort a list: [('A',(6,2,1,3)), ('B',(4,5,9,3)), ('C',(1,2,3,8))] by the last number, and if the last number is equal, then sort by the 3rd number. However, I'm unsure how to approach this. I used lambda to sort by the last number, but when the last numbers are equal, python automatically sorts by the first number.
Using the lambda, create a key which is a tuple of last number and third number:
mylist = [('B',(4,5,9,3)), ('C',(1,2,3,8)), ('A',(6,2,1,3))]
mylist.sort(key=lambda x:(x[1][-1], x[1][2]))
Outputs:
[('A', (6, 2, 1, 3)), ('B', (4, 5, 9, 3)), ('C', (1, 2, 3, 8))]
You basically want to sort by the last element in each tuple, reversed. Python translates that english to code pretty well:
sorted(li,key=lambda x: tuple(reversed(x[-1])))
Out[4]: [('A', (6, 2, 1, 3)), ('B', (4, 5, 9, 3)), ('C', (1, 2, 3, 8))]
Related
What is the difference between
mylist = reversed(sorted(mylist))
vs
mylist = sorted(mylist, reverse=True)
Why would one be used over the other?
How about for a stable sort on multiple columns such as
mylist.sort(key=itemgetter(1))
mylist.sort(key=itemgetter(0))
mylist.reverse()
is this the same as
mylist.sort(key=itemgetter(1), reverse=True)
mylist.sort(key=itemgetter(0), reverse=True)
?
You have hit on exactly the difference. Since Timsort is stable, sorting on the reverse versus reversing the sort will leave the unsorted elements in reverse orders.
>>> s = ((2, 3, 4), (1, 2, 3), (1, 2, 2))
>>> sorted(s, key=operator.itemgetter(0, 1), reverse=True)
[(2, 3, 4), (1, 2, 3), (1, 2, 2)]
>>> list(reversed(sorted(s, key=operator.itemgetter(0, 1))))
[(2, 3, 4), (1, 2, 2), (1, 2, 3)]
The interesting invariant is:
list(reversed(sorted(reversed(data)))) == sorted(data, reverse=True)
The other respondents are correct that the difference has to do with sort stability which preserves the order of equal keys. And also sorted() returning a list while reversed() returns an iterator.
You get a list for sorted() but reversed() returns an iterator
I have a list of pairs of numbers with the list sorted by the number on the right- eg:
[(7, 1)
(6, 2)
(5, 3)
(8, 5)
(9, 7)
(4, 9)]
and I want to get out the strands that are linked. A strand is defined as:
x->y->z
where tuples exist:
(y, x)
(z, y)
The strands in the above example are:
1->7->9->4
2->6
3->5->8
in the above example. I cannot think of any sensible code; as simple iteration with a counting variable will cause significant repeats. Please give me some pointers.
There's an easier way to do this than a real linked list. Since there's no real need for traversal, you can simply build regular lists as you go.
ts = [(7, 1),
(6, 2),
(5, 3),
(8, 5),
(9, 7),
(4, 9)]
def get_strands(tuples):
'''builds a list of lists of connected x,y tuples
get_strands([(2,1), (3,2), (4,3)]) -> [[1,2,3,4]]
Note that this will not handle forked or merging lists intelligently
'''
lst = []
for end, start in tuples:
strand = next((strand for strand in lst if strand[-1]==start), None)
# give me the sublist that ends with `start`, or None
if strand is None:
lst.append([start, end]) # start a new strand
else:
strand.append(end)
return lst
Demo:
In [21]: get_strands(ts)
Out[21]: [[1, 7, 9, 4], [2, 6], [3, 5, 8]]
I think the most complete solution is to create a graph from your data and then perform a topological sort on it. It will provide your expected result as long as the your graph doesn't have any cycles.
I have a list of tuples, each tuple contains two integers. I need to sort the the list (in reverse order) according to the difference of the integers in each tuple, but break ties with the larger first integer.
Example
For [(5, 6), (4, 1), (6, 7)], we should get [(4, 1), (6, 7), (5, 6)].
My way
I have already solved it by making a dictionary that contains the difference as the key and the tuple as the value. But the whole thing is a bit clumsy.
What is a better way?
Use a key function to sorted() and return a tuple; values will be sorted lexicographically:
sorted(yourlst, key=lambda t: (abs(t[0] - t[1])), t[0]), reverse=True)
I'm using abs() here to calculate a difference, regardless of which of the two integers is larger.
For your sample input, the key produces (1, 5), (3, 4) and (1, 6); in reverse order that puts (1, 6) (for the (6, 7) tuple) before (1, 5) (corresponding with (5, 6)).
Demo:
>>> yourlst = [(5, 6), (4, 1), (6, 7)]
>>> sorted(yourlst, key=lambda t: (abs(t[0] - t[1]), t[0]), reverse=True)
[(4, 1), (6, 7), (5, 6)]
Given this list=[('a','b',3),('d','e',3),('e','f',5)], if you'd like to sort by the number in descending order, but break ties (when counts are equal like with the '3' on this example) using ascending alphabetical order of the first element and then the second element repectively, the following code works:
sorted(list,key=lambda x: (-x[2],x[0],x[1]))
Here the '-' sign on the x[2] indicates it needs to be sorted in the descending order.
The output will be: [('e', 'f', 5), ('a', 'b', 3), ('d', 'e', 3)]
Referring to the below code, the first for loop can be easily used for the sorting in the dictionary and it works very well.
import operator
myExample = {'Item1': 3867, 'Item2': 20, 'Item3': 400, 'Item4': 100, 'Item5': 2870,
'Item6': 22, 'Item7': 528, 'Item8': 114}
for w in sorted(myExample, key=myExample.get, reverse=False):
print w, myExample[w]
print ("\n")
for w in sorted(myExample, key=operator.itemgetter(0)):
print w, myExample[w]
But somehow I was told by the other thread, it is advice to use operator.itemgetter(index) method to perform the sorting due to the efficiency reason. But the second for loop is never works in my case.
Perhaps I should go through the documentation first and this is what I get:
>>> itemgetter(1)('ABCDEFG')
'B'
>>> itemgetter(1,3,5)('ABCDEFG')
('B', 'D', 'F')
>>> itemgetter(slice(2,None))('ABCDEFG')
'CDEFG'
The example is simple, But to be honest, I don't know how to link this back to the dictionary case. How should I use the index inside the itemgetter and different index will have what kind of impact? I tried all index from 0 to 4 and none of them give me an ascending sorting result and error will occur starting from index 5.
In a document, there is a example for tuple case, but it's not works for the dictionary.
>>> inventory = [('apple', 3), ('banana', 2), ('pear', 5), ('orange', 1)]
>>> getcount = itemgetter(1)
>>> map(getcount, inventory)
[3, 2, 5, 1]
>>> sorted(inventory, key=getcount)
[('orange', 1), ('banana', 2), ('apple', 3), ('pear', 5)]
Back to the Origin, I still hope to understand how to use the index inside the itemgetter and what it does in different cases like tuple vs. dictionary vs. list vs. only a string vs. tuple inside a list, and etc.
Please advise.
I want to take a list, for instance List = [1,2,2], and generate its permutations. I can do this with:
NewList = [list(itertools.permutations(List))]
and the output is:
[[(1, 2, 2), (1, 2, 2), (2, 1, 2), (2, 2, 1), (2, 1, 2), (2, 2, 1)]]
The Problem: itertools.permutations returns a list of length 1 whose only entry is the list of all permutations of List. That is:
NewList[0] == [(1,2,2),(1,2,2),(2,1,2),(2,2,1),(2,1,2),(2,2,1)]
and
NewList[1] does not exist.
I want the output to be a list where each entry is one of the permutations. That is
NewList[0] == (1,2,2)
NewList[1] == (1,2,2)
NewList[2] == (2,1,2)
...
NewList[5] == (2,2,1)
The Question: Is there a command that will produce the permutations of List in this way? Failing that, is there a way to access the 'individual elements' of [list(itertools.permutations(List))] so I can do things with them?
>>> from itertools import permutations
>>> list(permutations([1,2,2]))
[(1, 2, 2), (1, 2, 2), (2, 1, 2), (2, 2, 1), (2, 1, 2), (2, 2, 1)]
You don't need to put it in a list again. i.e Don't do [list(permutations(...))] (By doing [] you are making a nested list and hence are unable to access the elements using testList[index], though you could do testList[0][index] but it would be better to just keep it as a list of tuples.)
>>> newList = list(permutations([1, 2, 2]))
>>> newList[0]
(1, 2, 2)
>>> newList[3]
(2, 2, 1)
Now you can access the elements by using their indices.
Why can't you do this:
NewList = [list(itertools.permutations(List))][0]
or even just this:
NewList = list(itertools.permutations(List))
By doing [ list(itertools.permutations(List)) ], you put the list of permutations (the one that you want) inside of another list. So the fix would be to remove the outer []'s