0

How to get the sum of values of certain keys from a map in a more efficient and optimised way?

For example:

var myMap = "SOSSPSSQSSOR".groupBy(identity).mapValues(_.size).toMap
>>myMap: scala.collection.immutable.Map[Char,Int] = Map(Q -> 1, P -> 1, R -> 1, O -> 2, S -> 7)

myMap.sumExcludingValuesFor("S,O")

def sumExcludingValuesFor(s:String):Int = {
//return the sum of the values for keys except S, O
}

My implementation so far:

var charMap = "SOSSPSSQSSOR".toString.groupBy(identity).mapValues(_.size).toMap
var excludeChar = Set('S','O')
var mapExcludingSO = charMap.filterKeys { excludeChar.contains(_) == false }
println(mapOnlySO.values.toList.sum)

But looking for a better implementation than this.

Any help is highly apprecaited!

3
  • What problems did you have with your own implementation? "A more efficient and optimised way" THAN WHAT? Commented Oct 4, 2017 at 21:36
  • @Dima as you can see, that I have edited my question to show my implementation. And I do not really understand why the question is downvoted for that. But since I am new to scala, please do feel free to rectify me any time. Commented Oct 4, 2017 at 21:47
  • Your question was downvoted because SO is not a "write my code for free" resource. It is not a place for general code review (check out codereview.stackexchange.com if you are interested in that). A good SO question is one seeking a specific advice on a concrete problem. Commented Oct 5, 2017 at 0:09

3 Answers 3

2

One often overlooked fact is that you can use Scala collections as a functions.

  • Seq[A] is Int => A (partial, by index)
  • Set[A] is A => Boolean (membership check)
  • Map[K, V] is K => V (partial)

Allowing you to write:

myMap.keysIterator.filterNot("SO".toSet).map(myMap).sum

It will also avoid intermediate collections, being Iterator-based

Sign up to request clarification or add additional context in comments.

Comments

0

Once you've isolated the keys of interest, instead of building a new Map with them, use them to directly access the values to be summed.

val charMap = "SOSSPSSQSSOR".groupBy(identity).mapValues(_.length)
charMap.keySet.diff("SO".toSet).foldLeft(0)(_ + myMap(_)) // res0: Int = 3

2 Comments

works like charm! would you be kind enough to upvote my question if possible?! Thank you so much.
You think builging two new sets is better than building a new map? :)
0

Your implementation is fine. You could, probably, get a marginal improvement by eliminating intermediate collections, and a few unnecessary traversals and key lookups, but this would be an overkill for pretty much all practical purposes:

input
  .groupBy(identity)
  .foldLeft(0) { 
     case (s, ("S"|"O", _)) => s
     case (s, (_, v)) => s + v.size
  }

Comments

Your Answer

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