2012-12-02 100 views
1

我想知道按字母順序排列元組中第一個字符串的List[(String, String)]的簡單方法,同時刪除元組中第二個字符串的所有重複項。Scala根據屬性對元組列表進行排序

感謝您的建議!

+3

http://stackoverflow.com/a/3912833/298389 + .sortBy(_._ 1) –

回答

7

我們可以運行性能測試嗎?

val items = List("a" -> 0, "b" -> 1, "c" -> 0, "d" -> 0, "e" -> 1) 
items.groupBy(_._2).toList 
    .sortBy(_._2.head._1)(new Ordering[String]() { 
     override def compare(x: String, y: String) = { -x.compareTo(y) } 
    }) 
    .map(e => (e._2.head._1 -> e._1)) 

結果:

List((b,1), (a,0)) 
+1

自定義排序的要點是什麼?你爲什麼不使用'Ordering [String] .reverse'? –

+0

謝謝!我最終只使用了默認排序,效果很好 – Jin

+0

Jin可能希望以小寫字母排序字符串 - 這就是爲什麼在答案中使用了自定義順序 – idonnie

1

對於好奇,評論鏈接的答案仍然有效。

如果你已經有了TreeMap,那麼groupBy會構建TreeMaps。這條線與idonnie's相似,只是沒有必要重新排序。

TreeMap(data: _*) groupBy (_._2) map (p => (p._2.head._1, p._1)) 

我不確定爲什麼它不能從開箱即用的列表中創建TreeMap。我正在對抗感冒藥的霧。但是當人們發表這些問題時總是很有趣。

package object distinctby { 
    import scala.collection.IterableLike 
    import scala.collection.generic.CanBuildFrom 
    import scala.collection.mutable.{ Set => MutSet } 

    implicit class RichCollection[A, Repr](val xs: IterableLike[A, Repr]) extends AnyVal { 
    def distinctBy[B, That](f: A => B)(implicit cbf: CanBuildFrom[Repr, A, That]) = { 
     val builder = cbf(xs.repr) 
     val i = xs.iterator 
     val set = MutSet[B]() 
     while (i.hasNext) { 
     val o = i.next 
     val b = f(o) 
     if (!set(b)) { 
      set += b 
      builder += o 
     } 
     } 
     builder.result 
    } 
    } 
} 

package distinctby { 
    import scala.collection.generic.CanBuildFrom 
    import scala.collection.immutable.TreeMap 
    object Test extends App { 
    val data = List("eins"->"one","un"->"one","zwei"->"two","deux"->"two") 
    println(data) 
    println(data distinctBy (_._2)) 
    println(TreeMap((data map (_.swap)): _*)) 
    println(TreeMap((data.reverse map (_.swap)): _*)) 
    // groupBy yields a TreeMap of TreeMap, so head is the lexly first 
    println(TreeMap(data: _*) groupBy (_._2) map (p => (p._2.head._1, p._1))) 
    locally { 
     class CBF[A,B](implicit ord: Ordering[A]) 
     extends CanBuildFrom[List[(A, B)], (A,B), TreeMap[A,B]] { 
     def apply(from: List[(A,B)]) = TreeMap.newBuilder[A, B](ord) 
     def apply() = TreeMap.newBuilder[A, B] 
     } 
     implicit def cbf[A,B](implicit ord: Ordering[A]) = new CBF[A,B] 
     println(data.distinctBy[String, TreeMap[String, String]](_._2)(cbf[String, String]).toSeq) 
    } 
    } 
} 

List((eins,one), (un,one), (zwei,two), (deux,two)) 
List((eins,one), (zwei,two)) 
Map(one -> un, two -> deux) 
Map(one -> eins, two -> zwei) 
Map(eins -> one, deux -> two) 
ArrayBuffer((eins,one), (zwei,two)) 
1

我只是使用List的sorted方法來進行元組的默認排序。您也可以使用groupBy(idonnie也指出)爲每一對中的第二個項目獲取不同的值。這裏有一個小例子:

scala> val tuples = scala.util.Random.shuffle("abcd".permutations.map{_.splitAt(2)}.toList) // generate some test data 
tuples: List[(String, String)] = List((cb,ad), (dc,ab), (ba,dc), (bd,ca), (cb,da), (ca,db), (cd,ba), (cd,ab), (db,ca), (ba,cd), (ac,db), (ac,bd), (ab,cd), (ad,cb), (ca,bd), (bd,ac), (ad,bc), (db,ac), (da,bc), (da,cb), (bc,da), (dc,ba), (ab,dc), (bc,ad)) 

scala> tuples.sorted.groupBy(_._2).values.map(_.head).toList.sorted 
res0: List[(String, String)] = List((ab,cd), (ab,dc), (ac,bd), (ac,db), (ad,bc), (ad,cb), (bc,ad), (bc,da), (bd,ac), (bd,ca), (cd,ab), (cd,ba)) 

這似乎有點怪我,你沒有指定具體的方法來選擇該副本,以保持...這應該保持的第一個(第一有序字符串),這是我假設你想要的。如果你不關心哪一個被保留,那麼你可以消除第一個電話sorted。如果您將第一次調用sorted更改爲sortBy(_._1),這也可能會稍微更有效一些,但對於您的特定應用程序我不太瞭解,以瞭解它是否會產生真正的差異。

相關問題