Can someone help me to understand this code please:
tuple1 = (('a', 23), ('b', 37), ('c', 11), ('d', 29))
tuple1 = tuple(sorted(list(tuple1), key=lambda x: x[1]))
print(tuple1)
sorted is a function which can sort a list according to some criteria. The criteria can be customized by passing a function as the key parameter.
lambda is a way to define a function. So it can be used to specify the criteria for sorting.
Quoting the docs for sorted
key specifies a function of one argument that is used to extract a comparison key from each element in iterable (for example, key=str.lower). The default value is None (compare the elements directly).
Related
Define:
diction = {"Book":(1, 2), "Armchair":(2, 2), "Lamp":(1, 3)}
If one wants to sort this dictionary by item["key"][1] descendingly and by "keys" ascendingly, what will be the appropriate way?
Desired output:
diction = {"Lamp":(1, 3), "Armchair":(2, 2), "Book":(1, 2)}
After receiving the correct answer by Sinan Note that I did not ask about sorting either ascendingly or descendingly, that you sent me the relevant links! I asked about doing both at the same time which is not solved by the trick of minus given by Sinan.
The main idea is copied from here.
from collections import OrderedDict
diction = {"Book":(1, 2), "Armchair":(2, 2), "Lamp":(1, 3)}
diction_list = list(diction.items())
diction = OrderedDict(sorted(diction_list, key=lambda x: (-x[1][1], x[0])))
print(diction)
OrderedDict([('Lamp', (1, 3)), ('Armchair', (2, 2)), ('Book', (1, 2))])
Here is where the magic is happening:
sorted(diction_list, key=lambda x: (-x[1][1], x[0]))
sorted sorts stuff for you. It is very good at it. If you use the key parameter with sort, you can give it a function to be used on each item to be sorted.
In this case, we are giving at a lambda that returns the negative value from the tuples -x[1][1] (this is the second value in the tuple) and the key x[0]. The negative sign makes it sort in reverse. Of course, this would not work with non-numeric values.
The OrderedDict thing is not strictly necessary. Python keeps dict in order after version 3.6 I think (or was it 3.7?). OrderedDicts are always kept in the same order, so it is there that so our dict stays ordered independent of the Python version.
For a better way of doing this see the Sorting HOW TO in Python Documentation.
I noticed that the results are different of the two lines. One is a sorted list, while the other is a sorted dictionary. Cant figure out why adding .item will give this difference:
aa={'a':1,'d':2,'c':3,'b':4}
bb=sorted(aa,key=lambda x:x[0])
print(bb)
#['a', 'b', 'c', 'd']
aa={'a':1,'d':2,'c':3,'b':4}
bb=sorted(aa.items(),key=lambda x:x[0])
print(bb)
# [('a', 1), ('b', 4), ('c', 3), ('d', 2)]
The first version implicitly sorts the keys in the dictionary, and is equivalent to sorting aa.keys(). The second version sorts the items, that is: a list of tuples of the form (key, value).
When you iterate on dictionary then you get iterate of keys not (key, value) pair. The sorted method takes any object on which we can iterate and hence you're seeing a difference.
You can verify this by prining while iterating on the dict:
aa={'a':1,'d':2,'c':3,'b':4}
for key in aa:
print(key)
for key in aa.keys():
print(key)
All of the above two for loops print same values.
In the second example, items() method applied to a dictionary returns an iterable collection of tuples (dictionary_key, dictrionary_value). Then the collection is being sorted.
In the first example, a dictionary is automatically casted to an iterable collection of its keys first. (And note: only very first characters of each of them are used for comparinson while sorting, which is probably NOT what you want)
So for example
['John','John','Mike','Mike','Kate','Kate']
Should return:
[('John', 2), ('Kate', 2), ('Mike', 2)]
How can I write code so there is order instead of those three pairs just being in random order?
I need to sort the list of tuples by count from biggest to smallest unless there are ties, then I need to sort the times alphabetically.
This works:
>>> names = ['John','John','Mike','Mike','Kate','Kate']
>>> sorted(Counter(names).items(), key=lambda item: (-item[1], item[0]))
[('John', 2), ('Kate', 2), ('Mike', 2)]
The counter's items will give you tuples of (name, count). Normally you'd use Counter.most_common to get the items in order of their counts, but as far as I can tell, it only sorts by count and disregards any key (name) information in the sorting.
Since we have to re-sort again anyway, we might as well use sorted on the items instead. Since tuples sort lexicographically, and you want to sort primarily by the count, the key function should return a tuple of the format (count, name). However, since you want this to be decreasing by count, but increasing by name, the only thing we can do is return a tuple of the format (-count, name). This way, larger count will result in a lower value so it will sort before values with lower counts.
You can sort your result using sorted() function using the key argument to define how to sort the items:
result = [('John', 2), ('Kate', 2), ('Mike', 3)]
sorted_result = sorted(result, key=lambda x: (-x[1], x[0]))
As you want to sort the result in descending order on the count value and then the name in ascending order, so the key (-x[1], x[0]) will do the trick.
The sorted_result will be:
[('Mike', 3), ('John', 2), ('Kate', 2)]
There are two ways to do this. In the first method, a sorted list is returned. In the second method, the list is sorted in-place.
import operator
# Method 1
a = [('Mike', 2), ('John', 2), ('Kate', 2), ('Arvind', 5)]
print(sorted(a, key = lambda x : (x[0],)))
# Method 2
a = [('Mike', 2), ('John', 2), ('Kate', 2), ('Arvind', 5)]
a.sort(key=operator.itemgetter(0))
print(a)
I've declared a list of tuples that I would like to manipulate. I have a function that returns an option from the user. I would like to see if the user has entered any one of the keys 'A', 'W', 'K'. With a dictionary, I would say this: while option not in author.items() option = get_option(). How can I accomplish this with a list of tuples?
authors = [('A', "Aho"), ('W', "Weinberger"), ('K', "Kernighan")]
authors = [('A', "Aho"), ('W', "Weinberger"), ('K', "Kernighan")]
option = get_option()
while option not in (x[0] for x in authors):
option = get_option()
How this works :
(x[0] for x in authors) is an generator expression, this yield the [0]th element of each item one by one from authors list, and that element is then matched against the option. As soon as match is found it short-circuits and exits.
Generator expressions yield one item at a time, so are memory efficient.
How about something like
option in zip(*authors)[0]
We are using zip to essentially separate the letters from the words. Nevertheless, since we are dealing with a list of tuples, we must unpack it using *:
>>> zip(*authors)
[('A', 'W', 'K'), ('Aho', 'Weinberger', 'Kernighan')]
>>> zip(*authors)[0]
('A', 'W', 'K')
Then we simply use option in to test if option is contained in zip(*authors)[0].
There are good answers here that cover doing this operation with zip, but you don't have to do it like that - you can use an OrderedDict instead.
from collections import OrderedDict
authors = OrderedDict([('A', "Aho"), ('W', "Weinberger"), ('K', "Kernighan")])
Since it remembers its entry order, you can iterate over it without fear of getting odd or unusual orderings of your keys.
I am just a beginner in python. I have document score= {1:0.98876, 8:0.12245, 13:0.57689} which is stored in dictionary. The keys are corresponding to a series of document id and the values are corresponding to the score for each document id. How do I rank the document based on the scores?
inverse=[(value, key) for key, value in score.items()]
fmax=max(inverse)
I already found the maximum values by using the method above which return:
(0.98876,1)
But what I want is to rank the documents and store in a list:
{(0.98876,1),(0.57689,13),(0.12245,8)}
sorted(score.items(), key=lambda x:-x[1])
should do the trick
The order of the elements in a dictionary is not defined, so the result of the sorting has to be stored in a list (or an OrderedDict).
You should convert it to a list of tuples using items(). With sorted() you can sort them, the key parameter tells it to sort according to the inverse of the second tuple element.
Full example:
>>> score= {1:0.98876, 8:0.12245, 13:0.57689}
>>> sorted(score.items(), key=lambda x:-x[1])
[(1, 0.98875999999999997), (13, 0.57689000000000001), (8, 0.12245)]
>>> print [(y,x) for (x,y) in _]
[(0.98875999999999997, 1), (0.57689000000000001, 13), (0.12245, 8)]
This also shows how to reverse the elements in the tuple if you really want to do that.
if you want to modify original list inverse then use inverse.sort(reverse=True).
If you want to produce a new list and leave original list untouched, use sorted(inverse, reverse=True).
You don't need an intermediate list, however, just use score:
>>> sorted(score.items(), key=lambda x: x[1], reverse=True)
[(1, 0.98876), (13, 0.57689), (8, 0.12245)]
After your inverse method, this would do the trick:
ranked = inverse.sort()
And here's some more info on sorting in python: http://wiki.python.org/moin/HowTo/Sorting/
Sort the inverse list:
inverse.sort()
This will return the list in ascending order, if you want it in reverse order, reverse it also:
inverse.reverse()
use this:
inverse.sort(reverse=True)
have a look here for more info on sorting
if you want rank itens in dict:
score = {1:0.98876, 8:0.12245, 13:0.57689}
# get a list of items...
list = score.items()
print list
[(8, 0.12245), (1, 0.98875999999999997), (13, 0.57689000000000001)]
# Sort items.
list.sort()
print list
[(1, 0.98875999999999997), (8, 0.12245), (13, 0.57689000000000001)]
# reverse order
list.reverse()
print list
[(13, 0.57689000000000001), (8, 0.12245), (1, 0.98875999999999997)]