Why don't Scala Lists have an Ordering?

前端 未结 6 1576
攒了一身酷
攒了一身酷 2020-12-31 00:47

Is there a reason why there is no implicit Ordering for Lists in Scala?

val lists = List(List(2, 3, 1), List(2, 1, 3))
lists.sorted

error: could not find im         


        
相关标签:
6条回答
  • 2020-12-31 00:59

    Incidentally even before I fixed this you could do this other ways:

    scala> List[Iterable[Int]](List(2, 3, 1), List(2, 1, 3)).sorted
    res0: List[Iterable[Int]] = List(List(2, 1, 3), List(2, 3, 1))
    
    scala> List(List(2, 3, 1), List(2, 1, 3)).sorted(Ordering[Iterable[Int]])
    res1: List[List[Int]] = List(List(2, 1, 3), List(2, 3, 1))
    

    But now it works like you'd hope.

    Edit: due to sketchy divergence issues with the requisite implicit I moved it out of the default scope. Having an implicit conversion which acts across a bound like this:

    implicit def SeqDerived[CC[X] <: collection.Seq[X], T](implicit ord: Ordering[T]): Ordering[CC[T]]
    

    ...is a potential recipe for issues. It'll be available in 2.9, but you have to import it as follows.

    scala> val lists = List(List(2, 3, 1), List(2, 1, 3))
    lists: List[List[Int]] = List(List(2, 3, 1), List(2, 1, 3))
    
    scala> lists.sorted
    <console>:9: error: could not find implicit value for parameter ord: Ordering[List[Int]]
           lists.sorted
                 ^
    
    scala> import Ordering.Implicits._
    import Ordering.Implicits._
    
    scala> lists.sorted
    res1: List[List[Int]] = List(List(2, 1, 3), List(2, 3, 1))
    
    0 讨论(0)
  • 2020-12-31 01:02

    You can use sortWith. This doesn't take differently sized lists into account because zip will throw out the difference, but I think it does something like what you're after:

    lists.sortWith((a,b) => {
      a.zip(b).filterNot(x => x._1 == x._2) match {
        case Nil => true
        case t => t._1 < t._2
      }
    })
    
    0 讨论(0)
  • 2020-12-31 01:10

    I think it's an oversight. Lexicographic ordering does make sense on Seqs. We should add it to the standard library.

    0 讨论(0)
  • 2020-12-31 01:11

    The only really sensible total order over the class of List[Int] would be lexicographic (i.e, compare the first elements of the list, then the second if they are equal, the third if the seconds are equal, etc.). This isn't provided by the standard library, probably because there aren't that many cases where it's actually needed. It would be easy enough to create an implicit conversion from List[X] to Ordering[List[X]] that would implement that, and then you could simply import that conversion wherever you needed it.

    0 讨论(0)
  • 2020-12-31 01:18

    What you have is a list of lists, not a list of integers. What you are missing is a criteria for determining whether a list is <= another list, or not.

    That's what the error message says: I can't find a way to compare a list to another list, you should provide one explicitly.

    If your question was "why don't list have a built-in comparison method against other lists", well, that's just the way it is.

    0 讨论(0)
  • 2020-12-31 01:19

    In newer Scala versions (tested with 2.12.5) there's an Ordering for Iterable[A]. Just ascribe the right type to your variable lists:

    scala> val lists = List(List(2, 3, 1), List(2, 1, 3))
    lists: List[List[Int]] = List(List(2, 3, 1), List(2, 1, 3))
    
    scala> (lists: List[Iterable[Int]]).sorted
    res0: List[Iterable[Int]] = List(List(2, 1, 3), List(2, 3, 1))
    

    Or convert the elements to instances of Iterable[] (which is a no-op for instances of List[]):

    scala> lists.map(_.toIterable).sorted
    res1: List[Iterable[Int]] = List(List(2, 1, 3), List(2, 3, 1))
    
    0 讨论(0)
提交回复
热议问题