Reputation: 42100
This is a simple coding exercise. Given a list of integers output a vertical histogram showing how many of each number are in the input list. If the lis is empty output an empty string.
List(5, 2, 3)
*
*
* *
***
***
I wrote a function as follows:
def hist(l: List[Int]) = if(l.isEmpty) ""
else Range(l.max, 0, -1).map(i => l.map(x => if(i <= x) "*" else " ").mkString)
How would you solve this problem ?
P.S. Forgot to say you need to output the resulting strings
val r = hist(List(5, 2, 3))
r.foreach(s => println(s))
Upvotes: 2
Views: 492
Reputation: 12124
For the sake of readability I'd do this instead:
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 " "))
}
As I believe cases are easier to read and reason about than if statements
Running it looks like this:
scala> hlist(List(5, 2, 3)).foreach(x => println(x.mkString))
*
*
* *
***
***
Upvotes: 2
Reputation: 20415
Return type from empty list check differs from the general case; consider this update,
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 " "))
Then for List(5, 2, 3)
,
hist(List(5, 2, 3))
res: Vector(List(*, " ", " "), List(*, " ", " "), List(*, " ", *), List(*, *, *), List(*, *, *))
and so for vertical printing,
hist(List(5, 2, 3)).foreach(v => println(v.mkString))
*
*
* *
***
***
Update
Let val a = List(5, 2, 3)
, then a one-liner is like this,
a.map(v => " " * (a.max - v) + "*" * v).transpose.foreach(x => println(x.mkString))
Upvotes: 1
Reputation: 3435
A bit more verbose but I believe more Scala-way:
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)
}
}
Few good points:
1) you don't need to use if l.isEmpty
since Scala has Nil
for that
2) pattern matching is always good for decomposition
3) you need to have simple List[String]
as a result and not the IndexedSeq[List[String]]
, so use IndexedSeq.toString
method to convert
Upvotes: 0
Reputation: 30746
Here's how I'd write the function you implemented:
def hist(xs: Seq[Int]): String =
xs.map(i => Seq.fill(i)('*').padTo(xs.max, ' '))
.transpose.reverse.map(_.mkString).mkString("\n")
But wouldn't a histogram of Seq(5,2,3)
look more like
** *
12345
?
Upvotes: 4