scala – SortedSet map并不总是保留结果中的元素排序?
鉴于以下
Scala 2.9.2代码:
更新了非工作示例 import collection.immutable.SortedSet case class Bar(s: String) trait Foo { val stuff: SortedSet[String] def makeBars(bs: Map[String,String]) = stuff.map(k => Bar(bs.getOrElse(k,"-"))).toList } case class Bazz(rawStuff: List[String]) extends Foo { val stuff = SortedSet(rawStuff: _*) } // test it out.... val b = Bazz(List("A","B","C")) b.makeBars(Map("A"->"1","B"->"2","C"->"3")) // List[Bar] = List(Bar(1),Bar(2),Bar(3)) // Looks good? // Make a really big list not in order. This is why we pass it to a SortedSet... val data = Stream.continually(util.Random.shuffle(List("A","C","D","E","F"))).take(100).toList val b2 = Bazz(data.flatten) // And how about a sparse map...? val bs = util.Random.shuffle(Map("A" -> "1","B" -> "2","E" -> "5").toList).toMap b2.makeBars(bs) // res24: List[Bar] = List(Bar(1),Bar(-),Bar(5)) 我发现,在某些情况下,扩展Foo的类的makeBars方法不会返回已排序的List.实际上,列表排序并不反映SortedSet的顺序 关于上面的代码我不知道什么,Scala不会总是将SortedSet映射到具有SortedSet排序的元素的List? 解决方法
你对隐含的解决方案感到惊讶.
map方法需要一个与目标集合类型兼容的CanBuildFrom实例(在简单??情况下,与源集合类型相同)和mapper函数的返回类型. 在SortedSet的特定情况下,其隐式CanBuildFrom要求可以使用Ordering [A](其中A是映射器函数的返回类型).当map函数返回编译器已经知道如何查找Ordering的内容时,你就是好的: scala> val ss = collection.immutable.SortedSet(10,9,8,7,6,5,4,3,2,1) ss: scala.collection.immutable.SortedSet[Int] = TreeSet(1,10) scala> val result1 = ss.map(_ * 2) result1: scala.collection.immutable.SortedSet[Int] = TreeSet(2,10,12,14,16,18,20) // still sorted because Ordering[Int] is readily available scala> val result2 = ss.map(_ + " is a number") result2: scala.collection.immutable.SortedSet[String] = TreeSet(1 is a number,10 is a number,2 is a number,3 is a number,4 is a number,5 is a number,6 is a number,7 is a number,8 is a number,9 is a number) // The default Ordering[String] is an "asciibetical" sort,// so 10 comes between 1 and 2. :) 但是,当您的映射器函数返回一个未知Ordering的类型时,SortedSet上的隐式不匹配(具体而言,无法找到其隐式参数的值),因此编译器看起来是“向上”的兼容CanBuildFrom并从Set中找到通用的. scala> case class Foo(i: Int) defined class Foo scala> val result3 = ss.map(Foo(_)) result3: scala.collection.immutable.Set[Foo] = Set(Foo(10),Foo(4),Foo(6),Foo(7),Foo(1),Foo(3),Foo(5),Foo(8),Foo(9),Foo(2)) // The default Set is a hash set,therefore ordering is not preserved 当然,您可以通过简单地提供Ordering [Foo]的实例来解决这个问题: scala> implicit val fooIsOrdered: Ordering[Foo] = Ordering.by(_.i) fooIsOrdered: Ordering[Foo] = scala.math.Ordering$$anon$9@7512dbf2 scala> val result4 = ss.map(Foo(_)) result4: scala.collection.immutable.SortedSet[Foo] = TreeSet(Foo(1),Foo(2),Foo(10)) // And we're back! 最后,请注意,玩具示例通常不会出现问题,因为Scala集合库具有针对小(n <= 6)集和映射的特殊实现. (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |