3

It is unclear to me how the following works:

In [1]: student_tuples = [('john', 'A', 15), ('jane', 'B', 12), ('dave', 'B', 10)]
In [2]: sorted(student_tuples, key=lambda student: student[2])
Out [2]: [('dave', 'B', 10), ('jane', 'B', 12), ('john', 'A', 15)] # sort by age

but,

In [3]: st = lambda student: student[2]
In [4]: st(student_tuples)
Out [4]: ('dave', 'B', 10)

Why does the [2] in the former sample refer to the index for the individual tuples, when in a lambda function it returns the 2nd tuple in the list?

DennisLi
  • 3,915
  • 6
  • 30
  • 66
P. Prunesquallor
  • 561
  • 1
  • 10
  • 26
  • 4
    It refers to item 2 of whatever the function is called on. You're not calling it on what `sorted` calls it on. – user2357112 May 07 '18 at 22:16
  • 4
    A key function is applied to each element individually, not the iterable as a whole. You can, for example, sort by absolute value, even though lists don't have an absolute value. `sorted([1, 2, -3], key=abs)` – Patrick Haugh May 07 '18 at 22:17
  • `sorted` function is iterable: `help(sorted)` provides: > `sorted(iterable, /, *, key=None, reverse=False)` > Return a new list containing all items from the iterable in ascending order. – Luke Mlsna May 07 '18 at 22:29

1 Answers1

5

Because when you're sorting, the key function is called once for every element of the list being sorted. That's why it's lambda student: not lambda student_tuples: (not that the naming of parameters changes anything, just explaining the naming choice).

You can see this directly by printing the argument of the key function:

student_tuples = [('john', 'A', 15), ('jane', 'B', 12), ('dave', 'B', 10)]

def my_key(student):
    print(student)
    return student[2]

sorted(student_tuples, key=my_key)
# calls to my_key print:
# ('john', 'A', 15)
# ('jane', 'B', 12)
# ('dave', 'B', 10)

my_key(student_tuples)
# prints (not returns):
# [('john', 'A', 15), ('jane', 'B', 12), ('dave', 'B', 10)]
Alex Hall
  • 34,833
  • 5
  • 57
  • 89