【问题标题】:Vertical Histogram in ScalaScala中的垂直直方图
【发布时间】:2014-08-14 06:50:36
【问题描述】:

这是一个简单的编码练习。给定一个整数列表,输出一个垂直直方图,显示输入列表中每个数字的数量。如果 lis 为空,则输出一个空字符串。

List(5, 2, 3)

*  
*  
* *
***
*** 

我写了一个函数如下:

def hist(l: List[Int]) = if(l.isEmpty) "" 
  else Range(l.max, 0, -1).map(i => l.map(x => if(i <= x) "*" else " ").mkString)

你会如何解决这个问题?

附:忘了说需要输出结果字符串

val r = hist(List(5, 2, 3))
r.foreach(s => println(s))

【问题讨论】:

  • 在 Scala 直方图计算中也可以考虑 stackoverflow.com/q/24536215/3189923
  • 注解更新...
  • 感谢您的更新。我认为这可能是解决它的正确方法。让我们等待投票。

标签: scala scala-collections


【解决方案1】:

我会这样写你实现的函数:

def hist(xs: Seq[Int]): String =
  xs.map(i => Seq.fill(i)('*').padTo(xs.max, ' '))
    .transpose.reverse.map(_.mkString).mkString("\n")

但是Seq(5,2,3) 的直方图不会看起来更像

 ** *
12345

?

【讨论】:

  • 谢谢。换位可能是解决问题的正确方法。
【解决方案2】:

为了可读性,我会这样做:

def hist: List[Int] => IndexedSeq[List[String]] = {
  case Nil => Vector(List("")) 
  case xs  => Range(xs.max, 0, -1).map(i => xs.map(x => if(i <= x) "*" else " "))
}

我相信案例比 if 语句更容易阅读和推理

运行起来是这样的:

scala> hlist(List(5, 2, 3)).foreach(x => println(x.mkString))
*
*
* *
***
***

【讨论】:

    【解决方案3】:

    空列表检查的返回类型与一般情况不同;考虑这次更新,

    def hist(l: List[Int]): IndexedSeq[List[String]] = 
      if(l.isEmpty) 
        Vector(List("")) 
      else 
        Range(l.max, 0, -1).map(i => l.map(x => if (i <= x) "*" else " "))
    

    那么对于List(5, 2, 3)

    hist(List(5, 2, 3))
    res: Vector(List(*, " ", " "), List(*, " ", " "), List(*, " ", *), List(*, *, *), List(*, *, *))
    

    对于垂直打印,

    hist(List(5, 2, 3)).foreach(v => println(v.mkString))
    
    *  
    *  
    * *
    ***
    ***
    

    更新

    val a = List(5, 2, 3),那么单行就是这样,

    a.map(v => " " * (a.max - v) + "*" * v).transpose.foreach(x => println(x.mkString))
    

    【讨论】:

    • 喜欢oneliner。现在我认为先构建一个水平直方图然后转置它确实要好得多。
    • 现在注意到@ChrisMartin 已经提供了与此答案中的更新非常相似的想法,因此要归功于他的方法。 :)
    • 是的。看起来@ChrisMartin 的解决方案是第一个。它也很好,但看起来有点冗长。
    • @Michael 先同意,但更详细
    【解决方案4】:

    有点冗长,但我相信更多的 Scala 方式:

    object Histogram {
      def hist(list:List[Int]):List[String] ={
        val max = list.max
        val matrix = list match{
          case Nil => Nil
          case _ =>{
            list map (l => "*" * l)
          }.map{
            s => s + (" " * (max - s.length))
          }
        }
    
        (0 to max-1).reverse map (
          i => (for (s <- matrix) yield s(i).toString).mkString
        ) toList
      }
    
      def main(args:Array[String]):Unit ={
        hist(List(5,2,3,7,4)).foreach(println)
      }
    }
    

    几个优点: 1)你不需要使用 if l.isEmpty 因为Scala有Nil

    2) 模式匹配总是有利于分解

    3)结果你需要简单的List[String]而不是IndexedSeq[List[String]],所以使用IndexedSeq.toString方法来转换

    【讨论】:

      猜你喜欢
      • 2012-10-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-11-15
      • 2014-04-15
      • 1970-01-01
      • 2011-08-27
      • 1970-01-01
      相关资源
      最近更新 更多