I have a string "abbbbccdddd" and the function should return "a1b4c2d4".
This is what I have written in Scala.
Iterative-version
def compress(str: String) = {
val chars = List(str).flatten.map(_.toString) ++ List(null)
var result: String = ""
var lookBack: String = chars.head
var occurance: Int = 0
chars.foreach { c =>
if (c != lookBack) {
result = result + lookBack.toString + occurance
occurance = 0
}
occurance = occurance + 1
lookBack = c
}
result
}
Recursive-version
def compress(str: String): String = {
def compressHandler(str: String, lookBack: String, occurance: Int, result: String): String = {
if(str.isEmpty) {
result
} else if(str.head.toString == lookBack) {
compressHandler(str.drop(1), str.head.toString, occurance + 1, result)
} else {
compressHandler(str, str.head.toString, 0, result + lookBack + occurance)
}
}
compressHandler(str + "0", str.head.toString, 0, "")
}
Scala — being a functional language should have much better solutions!
How to improve second (by somehow using map/reduce/fold) and how to do the first following concept of immutability (purely functional)?
-
\$\begingroup\$ You can use mutable vars or collections. It is not tabu. The most important things are simplicity and sufficient speed. For speed you should not use head, tail and reverse for String in this task. For simplisity you can use simple counter var and index. In some tasks you should prefer FP, in some -- iterative, in some -- special functions. I advice you to see Scala Days with Martin Odersky for 2013 оr 2014 year \$\endgroup\$Mikhail Ionkin– Mikhail Ionkin2020年07月26日 14:21:32 +00:00Commented Jul 26, 2020 at 14:21
-
\$\begingroup\$ Scala days: Scala with style youtu.be/kkTFx3-duc8 \$\endgroup\$Mikhail Ionkin– Mikhail Ionkin2020年07月26日 14:27:51 +00:00Commented Jul 26, 2020 at 14:27
2 Answers 2
Here's my take using foldLeft:
def compress(s: String) = {
val a : List[(Char,Int)] = List()
s.toCharArray.foldLeft(a)((acc, elem) => acc match {
case Nil => (elem, 1) :: Nil
case (a, b) :: tail =>
if (a == elem) (elem, b + 1) :: tail else (elem, 1) :: acc
}).reverse
.map{ case (a, b) => a.toString + b }
.mkString("")
}
Note: I have assumed that order matters. That is, aabbbaa
will reduce to a2b3a2
-
\$\begingroup\$ Cool stuff! However we can desugar this and get rid of
._1
and._2
but it seems perfect to me. \$\endgroup\$Fahad Siddiqui– Fahad Siddiqui2020年05月08日 09:38:31 +00:00Commented May 8, 2020 at 9:38 -
\$\begingroup\$ changed to get rid of
._1
and._2
\$\endgroup\$Luqman– Luqman2020年05月08日 09:44:58 +00:00Commented May 8, 2020 at 9:44 -
2\$\begingroup\$ Welcome to code review. This answer is an alternate solution which is fine on stackoverflow.com but is not a good answer on code review. A good answer may not contain any code at all, but it must contain at least one meaningful observation about the code posted in the the question. Code can be used as examples to support the observations about the posters code. \$\endgroup\$2020年05月08日 13:53:29 +00:00Commented May 8, 2020 at 13:53
I would suggest omitting the allocation of extra space. Try to start with:
object Solution:
def compress(str: String): String =
val (sb, _) =
Vector.range(0, str.size + 1).foldLeft(StringBuilder(), 0) {
case ((sb, occurance), i) =>
if i == 0
???
else if i == str.size
???
else if str(i) == str(i - 1)
???
else
???
}
sb.toString