【问题标题】:How to sort uppercase and lowercase Strings in Scala如何在Scala中对大写和小写字符串进行排序
【发布时间】:2014-12-26 23:10:26
【问题描述】:

Scala 中有一个字符串列表。让我们假设这些字符串只包含英文字母(小写和大写)。以下是示例列表:

val l1 = List("ab","aa", "bc","Aa", "Ab", "Ba", "BB")

当我们使用以下代码对其进行排序时:

l1.sortWith(_ < _)  

我们将收到:

List(Aa, Ab, BB, Ba, aa, ab, bc)

所以这种排序使用以下字母之间的关系:

A < B < C < ... < a < b < c ...

我们也可以使用:

l1.sortWith(_.toLowerCase < _.toLowerCase)

接收:

List(aa, Aa, ab, Ab, Ba, BB, bc)

所以现在字母之间的关系是:

(a=A) < (b=B) < (c=C) ...

但是如何在 Scala 中使用以下字母顺序对它们进行排序? :

a < A < b < B < c < C ...

所以结果应该是;

List(aa, ab, Aa, Ab, bc, Ba, BB)

【问题讨论】:

    标签: scala sorting


    【解决方案1】:
    scala> def compareChar(c1:Char, c2:Char) = {
             if ( c1 == c2 ) None
             else if (c1.toLower == c2.toLower) Some(c2.isUpper)
             else Some(c1.toLower < c2.toLower)
           }
    compareChar: (c1: Char, c2: Char)Option[Boolean]
    
    scala> def compareString(s1:String, s2:String) : Boolean = {
             (s1 zip s2).collectFirst {
               case (c1,c2) if (compareChar(c1,c2).isDefined) => compareChar(c1,c2).get
             }.getOrElse(s1.length < s2.length)
           }
    compareString: (s1: String, s2: String)Boolean
    
    scala> l1 sortWith compareString
    res02: List[String] = List(aa, ab, Aa, Ab, bc, Ba, BB)
    

    编辑: 内联版本:

    def compareString(s1:String, s2:String) : Boolean = {
      (s1 zip s2).collectFirst {
        case (c1, c2) if c1 == c2 => compareString(s1.tail, s2.tail)
        case (c1, c2) if c1.toLower == c2.toLower => c2.isUpper // same letter, different case, uppercase wins
        case (c1, c2) => c1.toLower < c2.toLower
      }.getOrElse(s1.length < s2.length) // same prefix, the longest string is bigger
    }
    

    scala> val l1 = List("ab","aa", "bc","Aa", "Ab", "Ba", "BB")
    l1: List[String] = List(ab, aa, bc, Aa, Ab, Ba, BB)
    
    scala> l1 sortWith compareString
    res0: List[String] = List(aa, ab, Aa, Ab, bc, Ba, BB)
    
    scala> List("ABC","AB") sortWith compareString
    res1: List[String] = List(AB, ABC)
    

    【讨论】:

    • List("ABC","AB") sortWith compareString 出乎意料。我会在 case 块中内联 compareChar。 if 守卫中不需要括号。此外,如果您逐字发布 REPL 成绩单,那么我们可以剪切/粘贴它。
    • @som-snytt:你说得对,我修复了“相同前缀/不同长度”错误。还使用“内联 compareChar”版本更新了答案(实际上比我的第一个版本更容易阅读)。
    【解决方案2】:
    scala> import math.Ordering.Implicits._
    import math.Ordering.Implicits._
    
    scala> val words = List("ab","aa", "bc","Aa", "Ab", "Ba", "BB")
    words: List[String] = List(ab, aa, bc, Aa, Ab, Ba, BB)
    
    scala> words sortBy (_ map (c => if (c.isUpper) 2 * c + 1 else 2 * (c - ('a' - 'A'))))
    res0: List[String] = List(aa, ab, Aa, Ab, bc, Ba, BB)
    

    【讨论】:

      【解决方案3】:

      试试这个

        val l1 = List("ab","aa", "bc","Aa", "Ab", "Ba", "BB")
        def comp[T <: String](a: T, b: T) = {
          def _comp(i: Int): Boolean = try {
            val (l, r) = (a(i), b(i))
            if (l == r) _comp(i+1) else l.toLower < r.toLower
          } catch {
            case e: IndexOutOfBoundsException => true
          }
          _comp(0)
        }
        println(l1.sortWith(comp)) // List(aa, ab, Aa, Ab, bc, Ba, BB)
      

      【讨论】:

        【解决方案4】:

        tailrec优化方案:

        def comp(x: String, y: String): Boolean = {
          @tailrec
          def go(xs: List[Char], ys: List[Char]): Boolean = {
            (xs, ys) match {
              case (hx :: tx, hy :: ty) =>
                if (hx == hy) go(tx, ty)
                else if (hx.toLower == hy.toLower) hx.isLower
                else if (hx.isLower) hx < hy
                else hx < hy.toUpper
              case (Nil, _) => true
              case (_, Nil) => false
            }
          }
          go(x.toList, y.toList)
        }
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2019-07-10
          • 1970-01-01
          • 2018-06-14
          • 1970-01-01
          • 2010-10-08
          • 1970-01-01
          • 1970-01-01
          • 2018-03-16
          相关资源
          最近更新 更多