Özel Python listesi sıralaması


98

Bazı eski kodumu yeniden düzenliyordum ve şununla karşılaştım:

alist.sort(cmp_items)

def cmp_items(a, b):
    if a.foo > b.foo:
        return 1
    elif a.foo == b.foo:
        return 0
    else:
        return -1

Kod çalışıyor (ve bunu 3 yıl önce yazmıştım!) Ancak Python belgelerinde belgelenen bu şeyi bulamıyorum ve herkes sorted()özel sıralamayı uygulamak için kullanıyor . Birisi bunun neden işe yaradığını açıklayabilir mi?


sorted()ve sort()aynı şekilde özel sıralama sunarak, çağrı geleneğindeki farkı modulo.
Russell Borogove

2
Gerçekte, bir keyparametre kullanmanın bir cmpişlevi iletmeye tercih edilmesidir . (
Sonrası

Bu biraz belirsiz, listedeki öğelerin ne olduğuna bağlı; kodunuz bir niteliğe sahip olmasını gerektirir foo, aksi takdirde patlar. Daha özel bir tanımlamaya __lt__(), ardından sınıf için yöntem sorted()ve list.sort()out-of-the-box çalışacaktır. (Btw, nesnelerin artık tanımlanması gerekmiyor __cmp__(), sadece __lt__().
Şuna

Yanıtlar:


60

Belgeli burada .

Sort () yöntemi, karşılaştırmaları kontrol etmek için isteğe bağlı bağımsız değişkenler alır.

cmp, ilk bağımsız değişkenin ikinci bağımsız değişkenden küçük, ona eşit veya ikinci bağımsız değişkenden daha büyük olmasına bağlı olarak negatif, sıfır veya pozitif bir sayı döndürmesi gereken iki bağımsız değişkenin (liste öğeleri) özel bir karşılaştırma işlevini belirtir: cmp = lambda x, y : cmp (x.lower (), y.lower ()). Varsayılan değer yok.


Teşekkürler miles82 Burayı kontrol ediyordum ve metot imzası docs.python.org/tutorial/datastructures.html
Lorenzo

Bağlantı verdiğiniz sayfada aynı metni görmüyorum. Dokümantasyon değişti mi? Ayrıca kullanmaya çalıştığımda cmpanlıyorum TypeError: 'cmp' is an invalid keyword argument for this function. Burada neler oluyor?
HelloGoodbye

2
@HelloGoodbye sort () Bu dokümanlar bağlantı Python 2 için Eski dokümanlar bulabilirsiniz eski bir cevaptır Python 3'te bir cmp argüman yok burada veya hakkında daha fazla okumak burada . Python 3 kullanıyorsanız, bunun yerine anahtar argümanını kullanın.
miles82

Peki ya gerçekten bir karşılaştırma işlevi sağlamak istiyorsanız? Bir dizedeki sayıları (herhangi bir uzunlukta, açgözlülükle seçilmiş), karakterlerin başka türlü nasıl ele alındığına eşdeğer bir sembol olarak ele almak istiyorum. Bir karşılaştırma işlevi sunabilirsem bunu önemsiz bir şekilde nasıl başaracağımı biliyorum, ancak bir anahtar işlev sağlamam gerekip gerekmediğini. Bu neden değiştirildi?
HelloGoodbye

Sanırım dizede bulunan her sayı, Levenshtein kodlaması gibi, sayıları sözlükbilimsel olarak sıralayan bir kodlama kullanılarak kodlanırsa yine de başarılabilir . Ancak bunu sort, Python 3'te bir karşılaştırma işlevini argüman olarak almayan ve gerçekten yapmak istediğim bir şey olarak görmeyen gerçeğine bir çözüm olarak düşünüyorum.
HelloGoodbye

108

Yan not olarak, aynı sıralamayı uygulamak için daha iyi bir alternatif:

alist.sort(key=lambda x: x.foo)

Veya alternatif olarak:

import operator
alist.sort(key=operator.attrgetter('foo'))

Check out Sıralama Nasıl Yapılır , çok yararlıdır.


1
Operatör hakkında TIL, çok kullanışlı.
ffledgling

16

Tıpkı bu örnek gibi. Bu listeyi sıralamak istiyorsunuz.

[('c', 2), ('b', 2), ('a', 3)]

çıktı:

[('a', 3), ('b', 2), ('c', 2)]

tuple'ları ikinci öğeye, ardından ilk öğeye göre sıralamanız gerekir:

def letter_cmp(a, b):
    if a[1] > b[1]:
        return -1
    elif a[1] == b[1]:
        if a[0] > b[0]:
            return 1
        else:
            return -1
    else:
        return 1

Ardından bunu bir anahtar işleve dönüştürün:

from functools import cmp_to_key
letter_cmp_key = cmp_to_key(letter_cmp))

Artık özel sıralama düzeninizi kullanabilirsiniz:

[('c', 2), ('b', 2), ('a', 3)].sort(key=letter_cmp_key)

4
Hangi listeyi sıralayacağını nasıl biliyor?
Cameron Monks

2
@CameronMonks yourList.sort (letter_cmp)
kebab-case

7

Bu Python 3'te çalışmaz.

Eski tip karşılaştırma işlevlerinin de çalışması için functools cmp_to_key'i kullanabilirsiniz.

from functools import cmp_to_key

def cmp_items(a, b):
    if a.foo > b.foo:
        return 1
    elif a.foo == b.foo:
        return 0
    else:
        return -1

cmp_items_py3 = cmp_to_key(cmp_items)

alist.sort(cmp_items_py3)

1

Birçoğunun zaten iyi cevaplar verdiğini biliyorum. Bununla birlikte, herhangi bir kütüphaneyi içe aktarmadan güzel ve kolay bir yöntem önermek istiyorum.

l = [(2, 3), (3, 4), (2, 4)]
l.sort(key = lambda x: (-x[0], -x[1]) )
print(l)
l.sort(key = lambda x: (x[0], -x[1]) )
print(l)

Çıktı olacak

[(3, 4), (2, 4), (2, 3)]
[(2, 4), (2, 3), (3, 4)]

Çıktı, tuple biçiminde sağladığımız parametrelerin sırasına göre sıralanacaktır.


0

Daha iyi:

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

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

Şuradan alınmıştır: https://docs.python.org/3/howto/sorting.html

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.