Sort lists with multiple parameters using lambda expression

Asked

Viewed 358 times

3

Given the class Ponto, the function ordenar sort the list elements by the following criteria: first value in x, afterward y and finally value in z.

Okay, the code works. But I’d like to understand how this expression lambda is "executed in practice" (what she does behind the scenes, let’s say). How something relatively complex can be executed on a single line of code?

Complete code:

import random


class Ponto():
    def __init__(self, x=0, y=0, z=0):
        self.x = x
        self.y = y
        self.z = z

    def __str__(self):
        return str(self.x) + ' ' + str(self.y) + ' '+str(self.z) 


def cria_pontos(quantos=10):
    lista = []
    for i in range(quantos):
        x = random.randint(0, 100) 
        y = random.randint(0, 100) 
        z = random.randint(0, 100)
        p = Ponto(x=x, y=y, z=z)
        lista.append(p) 
    return lista


def ordernar(lista=None):
    lista.sort(key=lambda p: (p.x, p.y, p.z))


def main():
    pontos = cria_pontos(quantos=5)
    pontos.append(Ponto(x=1,y=2,z=3))
    pontos.append(Ponto(x=2,y=3,z=2))
    pontos.append(Ponto(x=2,y=2,z=2))

    ordernar(lista=pontos)
    for p in pontos:
        print(p)

if __name__ == '__main__':
    main()

I created this class Ponto to use example to facilitate the understanding of my question. Please do not consider the conception of it.

  • 1

    Very good class design Ponto to have a minimal, simple and complete example

1 answer

5


The method sort, class list, when used with the parameter key will execute the sort as the value returned by the expression defined in key, not the value present in the list itself. For your case, it is used:

key=lambda p: (p.x, py. p.z)

That is, the expression that will be used will be a lambda expression that will convert an object of type Ponto in a tuple with the corresponding coordinates of the point. Natively, in Python, when comparing two tuples, the comparison gives value to value, from left to right, i.e., compares x, then y and finally z.

Therefore, considering a short list of points:

lista = [Ponto(x=1,y=2,z=3), Ponto(x=2,y=3,z=2), Ponto(x=2,y=2,z=2)]

When executing the sort function:

lista.sort(key=lambda p: (p.x, p.y, p.z))

Roughly speaking, what happens is:

  1. Sets an auxiliary list with the first value of the list: saida = [Ponto(x=1,y=2,z=3)];
  2. Takes the second value of the list, iterates over the auxiliary list and applies the lambda expression both in the value to be added and in the value present in the auxiliary list, comparing its returns:
    • The return of the lambda expression to the value to be added will be: (2, 3, 2);
    • Scroll through the auxiliary list and the return of the expression to the value in the auxiliary list will be: (1, 2, 3);
    • Compare the two tuples returned and, as the tuple of the value to be added will be after the tuple returned to the value in the auxiliary list, the value is inserted after;
    • The auxiliary list is then: saida = [Ponto(x=1,y=2,z=3), Ponto(x=2,y=3,z=2)];
  3. Take the third value from the list and repeat the process:
    • The return of the lambda expression of the first value of the auxiliary list will be: (1, 2, 3);
    • The return of the lambda expression to the added value will be: (2, 2, 2);
    • Comparing them, it is verified that the new value must be added after the first;
    • Then the same comparison is made with the second value:
    • The lambda expression return of the second value of the auxiliary list will be: (2, 3, 2);
    • Comparing them, it turns out that the new value should be inserted before the second;
    • Thus, the new value is inserted in the auxiliary list between the first and the second value, leaving: saida = [Ponto(x=1,y=2,z=3), Ponto(x=2,y=2,z=2), Ponto(x=2,y=3,z=2)];
  4. After iterations, the new list value is defined as the auxiliary list: lista = saida;

This way, after ordering, the list would be:

lista = [Ponto(x=1,y=2,z=3), Ponto(x=2,y=2,z=2), Ponto(x=2,y=3,z=2)]

Ordered according to the values of x, y and z, respectively. Function performance is not greatly affected by the use of the parameter key because, due to internal language implementations, the expression defined in key is called only once for each value in the list, regardless of how often this value is used in the sorting process.

  • If you want to know exactly what happens under the table, comments that I try to search directly in the source code what runs.

Browser other questions tagged

You are not signed in. Login or sign up in order to post.