จะใช้ฟังก์ชันเปรียบเทียบแบบกำหนดเองใน Python 3 ได้อย่างไร?


105

ในPython 2.xฉันสามารถส่งฟังก์ชันที่กำหนดเองไปยังฟังก์ชันการเรียงลำดับและ. เรียงลำดับได้

>>> x=['kar','htar','har','ar']
>>>
>>> sorted(x)
['ar', 'har', 'htar', 'kar']
>>> 
>>> sorted(x,cmp=customsort)
['kar', 'htar', 'har', 'ar']

เพราะในภาษาของฉันพยัญชนะมาพร้อมกับคำสั่งนี้

"k","kh",....,"ht",..."h",...,"a"

แต่ในPython 3.xดูเหมือนว่าจะไม่สามารถส่งผ่านcmpkeyword ได้

>>> sorted(x,cmp=customsort)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: 'cmp' is an invalid keyword argument for this function

มีทางเลือกอื่นหรือไม่หรือฉันควรเขียนฟังก์ชันเรียงลำดับของตัวเองด้วย?

หมายเหตุ: ฉันทำให้ง่ายขึ้นโดยใช้ "k", "kh" ฯลฯ อักขระจริงคือ Unicodes และซับซ้อนกว่านั้นบางครั้งมีสระมาก่อนและหลังพยัญชนะฉันได้ใช้ฟังก์ชันเปรียบเทียบแบบกำหนดเองดังนั้นส่วนนั้นก็โอเค มีปัญหาเพียงอย่างเดียวคือฉันไม่สามารถส่งผ่านฟังก์ชันการเปรียบเทียบที่กำหนดเองไปยัง sorted หรือ .sort


คุณได้ลองแค่sorted(x)ไหน?
SilentGhost

@SilentGhost เพื่อให้แน่ใจว่าฉันได้ลองอีกครั้งแน่นอนว่าใช้ไม่ได้เพราะภาษาต้นฉบับของฉันไม่ได้อยู่ในรายการโลแคลที่ระบบปฏิบัติการจะทำการเรียงลำดับ
คุณ

1
คุณสามารถรวม cmp ของคุณเป็นฟังก์ชันหลักได้ ค้นหาไซต์ HowToSorting สำหรับ cmp_to_key
Frank

นี่คือสิ่งที่คล้ายกันstackoverflow.com/questions/49327344/…
Eziz Durdyyev

คำตอบ:


53

ใช้keyอาร์กิวเมนต์ (และทำตามสูตรเกี่ยวกับวิธีการแปลงcmpฟังก์ชันเก่าของคุณเป็นkeyฟังก์ชัน)

functoolsมีฟังก์ชันที่cmp_to_keyกล่าวถึงในdocs.python.org/3.6/library/functools.html#functools.cmp_to_key


+1 ดูเหมือนว่าสูตรจะให้วิธีแก้ปัญหาแก่ฉัน แต่ฉันคิดว่าฉันจะสูญเสียประสิทธิภาพบางอย่างโดยส่งตัวดำเนินการเปรียบเทียบทั้งหมด< > = ไปยังชายกลางเนื่องจากการเรียงลำดับที่กำหนดเองดั้งเดิมของฉันเขียนด้วย C มันมีความเร็วประมาณ 1 / 2x ของ การจัดเรียงเริ่มต้น
คุณ

2
(เพิ่งดูโปรไฟล์ของคุณ) บริษัท ของคุณบล็อกการเข้าถึง Google และ StackOverflow ใช่หรือไม่ พวกเขาโง่ได้แค่ไหน? แต่เกี่ยวกับคำตอบของคุณ: ฉันสนใจเรื่องประสิทธิภาพที่ลดลงจริง คุณสามารถtimeitมันได้หรือไม่
Tim Pietzcker

4
ฉันได้ทำการวัดประสิทธิภาพแล้วดูเหมือนว่าช้ากว่าการส่งผ่านฟังก์ชันเปรียบเทียบ C ที่กำหนดเองโดยตรงประมาณ 4 เท่า
คุณ

2
จะเกิดอะไรขึ้นถ้าฉันต้องการทั้งฟังก์ชันคีย์และฟังก์ชัน cmp? ฉันต้องการจัดเรียงรายการพจนานุกรมตามคีย์ที่กำหนดเองในแต่ละพจนานุกรม sorted_rows = sorted(rows, key=itemgetter('name'), cmp=locale.strxfrm)ให้ TypeError: 'cmp' เป็นอาร์กิวเมนต์คำหลักที่ไม่ถูกต้องสำหรับฟังก์ชันนี้ใน Python 3.2 :(
Alex Bitek

4
functools มีฟังก์ชัน cmp_to_key ในไลบรารีมาตรฐาน: docs.python.org/3.6/library/functools.html
Martín Fixman


18

แทนที่จะเป็นศุลกากร () คุณต้องมีฟังก์ชันที่แปลแต่ละคำให้เป็นสิ่งที่ Python รู้วิธีจัดเรียงอยู่แล้ว ตัวอย่างเช่นคุณสามารถแปลแต่ละคำเป็นรายการตัวเลขโดยที่ตัวเลขแต่ละตัวแสดงถึงตำแหน่งที่ตัวอักษรแต่ละตัวปรากฏในตัวอักษรของคุณ สิ่งนี้:

my_alphabet = ['a', 'b', 'c']

def custom_key(word):
   numbers = []
   for letter in word:
      numbers.append(my_alphabet.index(letter))
   return numbers

x=['cbaba', 'ababa', 'bbaa']
x.sort(key=custom_key)

เนื่องจากภาษาของคุณมีตัวอักษรหลายอักขระฟังก์ชัน custom_key ของคุณจะต้องซับซ้อนมากขึ้นอย่างเห็นได้ชัด นั่นควรให้แนวคิดทั่วไปแก่คุณว่า


ขอบคุณ +1 นั่นคือวิธีที่ฉันคิด ICU แต่เนื่องจากภาษาของฉันไม่มีตัวแยกคำและไม่มีกฎมาตรฐานโรมันฉันจึงคิดว่าต้องใช้เวลาในการค้นคว้า
คุณ

10

python3 cmp_to_key lambda ตัวอย่างที่สมบูรณ์:

from functools import cmp_to_key

nums = [28, 50, 17, 12, 121]
nums.sort(key=cmp_to_key(lambda x, y: 1 if str(x)+str(y) < str(y)+str(x) else -1))

เปรียบเทียบกับการจัดเรียงวัตถุทั่วไป:

class NumStr:
    def __init__(self, v):
        self.v = v
    def __lt__(self, other):
        return self.v + other.v < other.v + self.v


A = [NumStr("12"), NumStr("121")]
A.sort()
print(A[0].v, A[1].v)

A = [obj.v for obj in A]
print(A)

4

ฉันไม่รู้ว่าจะช่วยได้ไหม แต่คุณสามารถตรวจสอบlocaleโมดูลได้ ดูเหมือนว่าคุณสามารถตั้งค่าภาษาเป็นภาษาของคุณและใช้locale.strcollเพื่อเปรียบเทียบสตริงโดยใช้กฎการเรียงลำดับของภาษาของคุณ


นั่นเป็นความจริงสำหรับภาษายอดนิยม แต่ภาษาของฉันไม่ได้รับการสนับสนุนอย่างเต็มที่จาก Operation Systems, ICU และ unicode.org ดังนั้นจึงไม่ต้องสงสัยเลย แต่ +1 สำหรับคำแนะนำที่ดี
คุณ

-2

ใช้keyอาร์กิวเมนต์แทน ใช้ฟังก์ชันที่รับค่าที่กำลังประมวลผลและส่งกลับค่าเดียวเพื่อให้คีย์ใช้จัดเรียงตาม

sorted(x, key=somekeyfunc)

3
คีย์ยอมรับฟังก์ชั่นพารามิเตอร์เดียวเท่านั้น cmp มี 2 พารามิเตอร์ซึ่งเป็นพฤติกรรมที่แตกต่างกัน และฉันเพิ่งทดสอบได้รับข้อผิดพลาดเนื่องจากคีย์เวิร์ดสำคัญส่งผ่านพารามิเตอร์เดียวเท่านั้นTypeError: customsort() takes exactly 2 positional arguments (1 given)
คุณ
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.