कोटलिन में कई मूल्यों पर आधारित / तुलना कैसे करें?


84

कहो कि मेरे पास एक है class Foo(val a: String, val b: Int, val c: Date)और मैं Fooतीनों गुणों के आधार पर सूची बनाना चाहता हूं । मैं इसे किस तरह लूं?

जवाबों:


146

कोटलिन की स्टडलिब इसके लिए कई उपयोगी सहायक विधियां प्रदान करती है।

सबसे पहले, आप compareBy()विधि का उपयोग कर एक तुलनित्र को परिभाषित कर सकते हैं और sortedWith()सूची की एक हल की गई प्रतिलिपि प्राप्त करने के लिए इसे विस्तार विधि में पास कर सकते हैं :

val list: List<Foo> = ...
val sortedList = list.sortedWith(compareBy({ it.a }, { it.b }, { it.c }))

दूसरा, आप सहायक विधि का उपयोग करके इसे Fooलागू Comparable<Foo>कर सकते हैं compareValuesBy():

class Foo(val a: String, val b: Int, val c: Date) : Comparable<Foo> {
    override fun compareTo(other: Foo)
            = compareValuesBy(this, other, { it.a }, { it.b }, { it.c })
}

फिर आप sorted()सूची की क्रमबद्ध प्रतिलिपि प्राप्त करने के लिए बिना पैरामीटर के विस्तार विधि को कॉल कर सकते हैं :

val sortedList = list.sorted()

क्रमबद्ध करने की दिशा

यदि आपको कुछ मूल्यों पर आरोही और अन्य मूल्यों पर उतरने की जरूरत है, तो stdlib उसके लिए भी कार्य करता है:

list.sortedWith(compareBy<Foo> { it.a }.thenByDescending { it.b }.thenBy { it.c })

प्रदर्शन के विचार

का varargसंस्करण compareValuesByबाईटकोड में इनबिल्ड नहीं है जिसका अर्थ है कि अनाम वर्ग लैम्बडा के लिए उत्पन्न होंगे। हालाँकि, यदि लंबोदर स्वयं राज्य पर कब्जा नहीं करते हैं, तो हर बार लैम्बदास को त्वरित करने के बजाय सिंगलटन इंस्टेंस का उपयोग किया जाएगा।

जैसा कि पॉल Woitaschek द्वारा टिप्पणी में कहा गया है , कई चयनकर्ताओं के साथ तुलना करने से वेरग कॉल के लिए हर बार एक सरणी तुरंत समाप्त हो जाएगी। आप इसे सरणी को निकालकर अनुकूलित नहीं कर सकते क्योंकि यह हर कॉल पर कॉपी किया जाएगा। दूसरी ओर आप क्या कर सकते हैं, तर्क को एक स्थिर तुलनित्र उदाहरण में निकालें और उसका पुन: उपयोग करें:

class Foo(val a: String, val b: Int, val c: Date) : Comparable<Foo> {

    override fun compareTo(other: Foo) = comparator.compare(this, other)

    companion object {
        // using the method reference syntax as an alternative to lambdas
        val comparator = compareBy(Foo::a, Foo::b, Foo::c)
    }
}

4
ध्यान दें कि यदि आप कई लैम्ब्डा फ़ंक्शन का उपयोग कर रहे हैं (वास्तव में एक जो इनलाइन के साथ एक अधिभार है), वे इनलाइन नहीं हैं । जिसका अर्थ है कि प्रत्येक कॉल comapreTo एक नई वस्तु बनाता है। यह रोकने के लिए कि आप चयनकर्ताओं को साथी ऑब्जेक्ट पर ले जा सकते हैं, इसलिए चयनकर्ताओं को केवल एक बार आवंटित किया गया है। मैंने यहां एक स्निप
पॉल Woitaschek

1
@KirillRakhman यह कार्यों के लिए एकल बनाता है लेकिन फिर भी सरणियाँ आवंटित करता है:ANEWARRAY kotlin/jvm/functions/Function1
पॉल वोइत्सेक

1
compareByकई लैंबडों के साथ कोटलिन 1.1.3 के साथ शुरू हर compareToकॉल पर नए सरणी आवंटित नहीं करेगा ।
इल्या

1
@ क्या आप मुझे इस तरह के अनुकूलन के लिए प्रासंगिक चैंज या अन्य जानकारी की ओर इशारा कर सकते हैं?
किरिल रहमान


0

यदि आप अवरोही क्रम में क्रमबद्ध करना चाहते हैं, तो आप स्वीकृत उत्तर का उपयोग कर सकते हैं:

list.sortedWith(compareByDescending<Foo> { it.a }.thenByDescending { it.b }.thenByDescending { it.c })

या एक्सटेंशन फ़ंक्शन बनाएं जैसे compareBy:

/**
 * Similar to
 * public fun <T> compareBy(vararg selectors: (T) -> Comparable<*>?): Comparator<T>
 *
 * but in descending order.
 */
public fun <T> compareByDescending(vararg selectors: (T) -> Comparable<*>?): Comparator<T> {
    require(selectors.size > 0)
    return Comparator { b, a -> compareValuesByImpl(a, b, selectors) }
}

private fun <T> compareValuesByImpl(a: T, b: T, selectors: Array<out (T) -> Comparable<*>?>): Int {
    for (fn in selectors) {
        val v1 = fn(a)
        val v2 = fn(b)
        val diff = compareValues(v1, v2)
        if (diff != 0) return diff
    }
    return 0
}

और का उपयोग करें: list.sortedWith(compareByDescending ({ it.a }, { it.b }, { it.c }))


0

यदि आपको कई क्षेत्रों के द्वारा सॉर्ट करने की आवश्यकता है, और कुछ क्षेत्र अवरोही और अन्य आरोही द्वारा जो आप उपयोग कर सकते हैं:

YOUR_MUTABLE_LIST.sortedWith(compareBy<YOUR_OBJECT> { it.PARAM_1}.thenByDescending { it.PARAM_2}.thenBy { it.PARAM_3})

1
यह मेरे उत्तर में शामिल है।
किरिल राखमन
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.