2012-12-02 236 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),这也可能会稍微更有效一些,但对于您的特定应用程序我不太了解,以了解它是否会产生真正的差异。

相关问题