268

In Python, I am trying to sort by date with lambda. I can't understand my error message. The message is:

<lambda>() takes exactly 1 argument (2 given)

The line I have is

a = sorted(a, lambda x: x.modified, reverse=True)
Niklas Rosencrantz
  • 23,939
  • 70
  • 214
  • 404

7 Answers7

453

Use

a = sorted(a, key=lambda x: x.modified, reverse=True)
#             ^^^^

On Python 2.x, the sorted function takes its arguments in this order:

sorted(iterable, cmp=None, key=None, reverse=False)

so without the key=, the function you pass in will be considered a cmp function which takes 2 arguments.

kennytm
  • 491,404
  • 99
  • 1,053
  • 989
  • 20
    You have good chance to learn to appreciate keyword parameter passing from this experience. – Tony Veijalainen Sep 22 '10 at 06:42
  • 1
    This is very old but, do you have any idea why the error code is misleading? Your answer sounds like possible Python is supplying `lambda` with another parameter since a `cmp` function takes 2? – SuperBiasedMan Sep 02 '15 at 09:04
  • 1
    @SuperBiasedMan the error is not misleading. `cmp`, a comparator function takes two arguments. If you don't specify that you are passing a `key`, it is assumed from the function parameters order that you are passing a comparator. Your lambda takes one parameter, therefore is not a valid comparator and that's what the error says. – Jezor May 24 '18 at 07:46
  • 1
    Python 2 and 3 seem to have different function declarations. I use Python 3, so there is no cmp anymore. In Python2, it is an `iterable`, what is it in Python 3? – Timo Dec 24 '20 at 09:51
48
lst = [('candy','30','100'), ('apple','10','200'), ('baby','20','300')]
lst.sort(key=lambda x:x[1])
print(lst)

It will print as following:

[('apple', '10', '200'), ('baby', '20', '300'), ('candy', '30', '100')]
Book Of Zeus
  • 48,853
  • 18
  • 173
  • 169
  • 1
    This does not work for string integers. Check this out! lst = [('999', '9'), ('303', '30'), ('343', '34')] lst.sort(key=lambda x: x[1]) print(lst) – Daniel Kua Jun 13 '20 at 04:26
  • 1
    The result is [('303', '30'), ('343', '34'), ('999', '9')] which is not sorted base on the second element in every list. – Daniel Kua Jun 13 '20 at 04:26
  • 1
    lst = [('candy','999','9'), ('apple','303','30'), ('baby','343','34')] lst.sort(key=lambda x:x[2]) print(lst) – Daniel Kua Jun 13 '20 at 04:28
  • 1
    [('apple', '303', '30'), ('baby', '343', '34'), ('candy', '999', '9')]. Which is not sorted base on 2 element too! – Daniel Kua Jun 13 '20 at 04:28
  • 4
    @DanielKua That's pretty simple to fix. You can just do `int(x[1])` instead of just `x[1]`. – M-Chen-3 Mar 16 '21 at 20:53
10

You're trying to use key functions with lambda functions.

Python and other languages like C# or F# use lambda functions.

Also, when it comes to key functions and according to the documentation

Both list.sort() and sorted() have a key parameter to specify a function to be called on each list element prior to making comparisons.

...

The value of the key parameter should be a function that takes a single argument and returns a key to use for sorting purposes. This technique is fast because the key function is called exactly once for each input record.

So, key functions have a parameter key and it can indeed receive a lambda function.

In Real Python there's a nice example of its usage. Let's say you have the following list

ids = ['id1', 'id100', 'id2', 'id22', 'id3', 'id30']

and want to sort through its "integers". Then, you'd do something like

sorted_ids = sorted(ids, key=lambda x: int(x[2:])) # Integer sort

and printing it would give

['id1', 'id2', 'id3', 'id22', 'id30', 'id100']

In your particular case, you're only missing to write key= before lambda. So, you'd want to use the following

a = sorted(a, key=lambda x: x.modified, reverse=True)
Tiago Martins Peres
  • 12,598
  • 15
  • 77
  • 116
3

In Python3:

    from functools import cmp_to_key
    def compare(i1,i2):
      return i1-i2
    events.sort(key=cmp_to_key(compare))
James L.
  • 9,851
  • 4
  • 37
  • 57
1

Take a look at this Example, you will understand:

Example 1:

a = input()
a = sorted(a, key = lambda x:(len(x),x))
print(a)

input: ["tim", "bob", "anna", "steve", "john","aaaa"]
output: ['bob', 'tim', 'aaaa', 'anna', 'john', 'steve']

input: ["tim", "bob", "anna", "steve", "john","aaaaa"]
output: ['bob', 'tim', 'anna', 'john', 'aaaaa', 'steve']


Example 2 (advanced):

a = ["tim", "bob", "anna", "steve", "john","aaaaa","zzza"]
a = sorted(a, key = lambda x:(x[-1],len(x),x))
print(a)

output: ['anna', 'zzza', 'aaaaa', 'bob', 'steve', 'tim', 'john']


Conclusion:

key = lambda x:(p1,p2,p3,p4,...,pn),
x is one element at a time from the stream of input.
p1,p2,p3...pn being properties based on which the stream of elements needs to be sorted.
based on priority order of p1>p2>p3>...>pn.
We can also add reverse=True, after the sorting condition, to sort the elements in reverse order.

Alessio Cantarella
  • 4,800
  • 3
  • 26
  • 31
0

Except for other complete answers, I know a great page for you to dive into.

You may find why there are key and cmp between python2.x and python3.

0

Another excellent example of a sorted function with lambda on Python3;

# list of sport teams with wins and losses
sportTeams = [("Royals", (18, 12)), ("Rockets", (24, 6)), 
                ("Cardinals", (20, 10)), ("Dragons", (22, 8)),
                ("Kings", (15, 15)), ("Chargers", (20, 10)), 
                ("Jets", (16, 14)), ("Warriors", (25, 5))]

# sort the teams by number of wins
sortedTeams = sorted(sportTeams, key=lambda t: t[1][0], reverse=True)
print(sortedTeams)

Output:

[('Warriors', (25, 5)), ('Rockets', (24, 6)), ('Dragons', (22, 8)), ('Cardinals', (20, 10)), ('Chargers', (20, 10)), ('Royals', (18, 12)), ('Jets', (16, 14)), ('Kings', (15, 15))]
smeric
  • 23
  • 5