3
\$\begingroup\$

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)?

asked May 8, 2020 at 7:53
\$\endgroup\$
2
  • \$\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\$ Commented Jul 26, 2020 at 14:21
  • \$\begingroup\$ Scala days: Scala with style youtu.be/kkTFx3-duc8 \$\endgroup\$ Commented Jul 26, 2020 at 14:27

2 Answers 2

3
\$\begingroup\$

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

answered May 8, 2020 at 9:31
\$\endgroup\$
3
  • \$\begingroup\$ Cool stuff! However we can desugar this and get rid of ._1 and ._2 but it seems perfect to me. \$\endgroup\$ Commented May 8, 2020 at 9:38
  • \$\begingroup\$ changed to get rid of ._1 and ._2 \$\endgroup\$ Commented 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\$ Commented May 8, 2020 at 13:53
0
\$\begingroup\$

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
answered Jul 10, 2020 at 7:48
\$\endgroup\$

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.