2013-01-21 15 views
18

इस कोड को एक स्काला वर्कशीट से है:स्काला में समूहबाई सूची सूची के ऑर्डर को क्यों बदलता है?

case class E(a: Int, b: String) 

val l = List(
    E(1, "One"), 
    E(1, "Another One"), 
    E(2, "Two"), 
    E(2, "Another Two"), 
    E(3, "Three") 
) 

l.groupBy(x => x.a)        
// res11: scala.collection.immutable.Map[Int,List[com.dci.ScratchPatch.E]] = 
// Map(
//  2 -> List(E(2,Two), E(2,Another Two)), 
//  1 -> List(E(1,One), E(1,Another One)), 
//  3 -> List(E(3,Three)) 
// ) 

आपको लगता है कि GroupBy मानचित्र दिखाए, लेकिन तत्वों के आदेश अब जिस तरह से वे पहले थे करने के लिए अलग-अलग हैं कि नोटिस जाएगा। ऐसा कोई विचार क्यों होता है, और इससे बचने का सबसे अच्छा तरीका क्या है?

+1

हाय @JacobusR तो मैं एक समारोह है कि लगातार बराबर कुंजी द्वारा समूहों के साथ अनुक्रम वर्ग रोगी शुरू कर दिया है। आपका प्रश्न SO पर कई अन्य प्रश्नों की तुलना में अच्छी तरह से लिखा गया है, लेकिन मुझे उम्मीद है कि आप अगली बार कोड स्वरूपण में अधिक प्रयास करने पर विचार करेंगे। यदि आप मुझसे पूछते हैं, तो यह लगभग पूरी तरह से पढ़ा नहीं जा सकता था, और अगर मैं पहले कोड को "पार्सिंग" करने में एक मिनट खर्च नहीं करना चाहता हूं तो मैं आमतौर पर एक प्रश्न का उत्तर देने के इच्छुक हूं :) – fresskoma

+0

हाय @ x3ro, एक लाख माफ़ी! यह पूरी तरह से मेरे दिमाग फिसल गया। मैं सवाल लिखने में व्यस्त था और कोई मेरे कार्यालय में चला गया, इसलिए मैंने इसे अभी पोस्ट किया। – Jack

+0

ओह, और संपादन @ x3ro के लिए धन्यवाद। यह बहुत बेहतर दिखता है :-) – Jack

उत्तर

19

जब तक आप विशेष रूप से सॉर्टेड मैप के उप प्रकार का उपयोग नहीं करते हैं, तो एक नक्शा (एक सेट की तरह) हमेशा एक अनिर्दिष्ट क्रम में होता है। चूंकि "groupBy" सॉर्ट किए गए मैप को वापस नहीं करता है, लेकिन केवल एक सामान्य अपरिवर्तनीय है। मैप और CanBuildFrom तंत्र का भी उपयोग नहीं करता है, मुझे लगता है कि आप यहां कुछ भी नहीं कर सकते हैं।

आप इसी विषय के उत्तर में इस विषय पर और अधिक पा सकते हैं, उदा। here

संपादित करें:

आप एक SortedMap (अपने कुंजी द्वारा आदेश दिया) के लिए नक्शे afterwarts परिवर्तित करना चाहते हैं, तो आप SortedMap(l.groupBy(_.a).toSeq:_*) (import scala.collection.immutable.SortedMap के साथ) कर सकते हैं। ...toSeq.sortWith(...).toMap मत करें क्योंकि यह परिणामस्वरूप मानचित्र में ऑर्डरिंग की गारंटी नहीं देगा।

+0

धन्यवाद। मानचित्र को ऑर्डर करने के लिए मैंने l.groupBy (\ _। A) .toSeq.sortWith (_._ 1 <_._ 1) .toMap का उपयोग किया था। बहुत सुंदर नहीं है, लेकिन हे, यह सोमवार है। – Jack

+0

या 'l.groupBy (_._ 1)। MapValues ​​(_। क्रमबद्ध) .view.force' –

+1

@ पीटर श्मिटज़: यह वही नहीं है। आपका स्निपेट मानों को टाइप करता है लेकिन ऑर्डरिंग समस्या कुंजी के साथ होती है। 'ToMap' के माध्यम से मानचित्र पर वापस लौटने के तथ्य को छोड़कर जैकबस आरआर सही है। –

8

डेटाबेस रिकॉर्ड से निपटने के दौरान मैं हर समय इसमें दौड़ता हूं। डेटाबेस उन्हें कुछ कुंजी द्वारा टाइप करता है लेकिन फिर समूह द्वारा इसे अनदेखा करता है!

class PimpedSeq[A](s: Seq[A]) { 

    /** 
    * Group elements of the sequence that have consecutive keys that are equal. 
    * 
    * Use case: 
    *  val lst = SQL("SELECT * FROM a LEFT JOIN b ORDER BY a.key") 
    *  val grp = lst.groupConsecutiveKeys(a.getKey) 
    */ 
    def groupConsecutiveKeys[K](f: (A) => K): Seq[(K, List[A])] = { 
    this.s.foldRight(List[(K, List[A])]())((item: A, res: List[(K, List[A])]) => 
     res match { 
     case Nil => List((f(item), List(item))) 
     case (k, kLst) :: tail if k == f(item) => (k, item :: kLst) :: tail 
     case _ => (f(item), List(item)) :: res 
     }) 
    } 
} 

object PimpedSeq { 
    implicit def seq2PimpedSeq[A](s: Seq[A]) = new PimpedSeq(s) 
} 

इसका इस्तेमाल करने के लिए::

import util.PimpedSeq._ // implicit conversion  
val dbRecords = db.getTheRecordsOrderedBy 
val groups = dbRecords.groupConsecutiveKeys(r => r.getKey)