Ještě jednou a lépe: seřazení podle více klíčů v Pythonu

Od Petr Zemek, 2014-03-08

Dneska se mrkneme na to, jak v Pythonu seřadit seznam podle více klíčů.

Původní kód

Dejme tomu, že máme seznam osob:

people = [
    {'name': 'Jiří', 'surname': 'Procházka', 'age': 23},
    {'name': 'Pavel', 'surname': 'Procházka', 'age': 45},
    {'name': 'Jiří', 'surname': 'Procházka', 'age': 22},
    {'name': 'Jana', 'surname': 'Merkel', 'age': 65},
    # ...
]

Naším úkolem je tento seznam seřadit podle příjmení, jména a věku. Tedy osoby se stejným příjmením se porovnají podle jména, a pokud i to je shodné, tak se vezme do úvahy věk.

První, co by vás po absolvování kurzu o algoritmech mohlo napadnout, tak je využít toho, že sort() v Pythonu je stabilní. To znamená, že zachovává vzájemné pořadí položek se stejným klíčem. Lze to tedy udělat tak, že se osoby seřadí nejdříve podle věku, pak podle jména a nakonec podle příjmení. Dále využijeme toho, že metodě sort() lze předat klíč, podle kterého se má porovnávat.

Naše první řešení by tedy mohlo vypadat takto:

people.sort(key=lambda p: p['age'])
people.sort(key=lambda p: p['name'])
people.sort(key=lambda p: p['surname'])

Proč takto raději ne?

Ač řešení funguje, tak trpí následujícími nevýhodami.

  • Rozsáhlost. Kód vykonávající jednoduchou činnost je tvořen třemi příkazy.
  • Čitelnost. Pro pochopení, co kódem autor myslel, je potřeba vědět, že sort() v Pythonu je stabilní a že tímto způsobem se dá řadit seznam podle více klíčů.
  • Opakující se kód. Třikrát je použit podobný kód.
  • Efektivita. Seznam se seřazuje na třikrát.

Jak to udělat lépe?

První zlepšení spočívá ve využití toho, že metodě sort() lze předat jako klíč funkci vracející ntici. Pokud se tak stane, tak se provede porovnání postupně podle uvedených hodnot. Kód výše by tedy šel přepsat takto:

people.sort(key=lambda p: (p['surname'], p['name'], p['age']))

Druhé zlepšení spočívá v použití standardního modulu operator, který poskytuje funkci itemgetter, která se nám postará o vybrání příslušných hodnot za nás:

from operator import itemgetter
 
people.sort(key=itemgetter('surname', 'name', 'age'))

Takto odpadne nutnost manuálního vytváření ntice a trojnásobného přístupu přes p. Kód je tak o něco kratší.

Obsah tohoto pole je soukromý a nebude veřejně zobrazen.

Filtrované HTML (využíváno)

  • Povolené HTML značky: <a href hreflang> <em> <strong> <cite> <code> <ul type> <ol start type> <li> <dl> <dt> <dd> <h2 id> <h3 id> <h4 id> <table>
  • Zvýraznění syntaxe kódu lze povolit přes následující značky: <code>, <blockcode>, <bash>, <c>, <cpp>, <haskell>, <html>, <java>, <javascript>, <latex>, <perl>, <php>, <python>, <ruby>, <rust>, <sql>, <text>, <vim>, <xml>, <yaml>.
  • Řádky a odstavce se zalomí automaticky.
  • Webové a e-mailové adresy jsou automaticky převedeny na odkazy.
CAPTCHA
11 + 1 =
Vyřešte tento jednoduchý matematický příklad a vložte výsledek. Např. pro 1+3 vložte 4.
Nějak se mi tady rozmohl spam, takže poprosím o ověření.