Spencer Chow
Spencer Chow

Reputation: 115

Cleaner way to find all indices of same value in Scala

I have a textfile like so

NameOne,2,3,3
NameTwo,1,0,2

I want to find the indices of the max value in each line in Scala. So the output of this would be

NameOne,1,2
NameTwo,2

I'm currently using the function below to do this but I can't seem to find a simple way to do this without a for loop and I'm wondering if there is a better method out there.

def findIndices(movieRatings: String): (String) = {
    val tokens = movieRatings.split(",", -1)
    val movie = tokens(0)
    val ratings = tokens.slice(1, tokens.size)
    val max = ratings.max
    var indices = ArrayBuffer[Int]()

    for (i<-0 until ratings.length) {
        if (ratings(i) == max) {
            indices += (i+1)
        }
    }

    return movie + "," + indices.mkString(",")

}

This function is called as so:

val output = textFile.map(findIndices).saveAsTextFile(args(1))

Just starting to learn Scala so any advice would help!

Upvotes: 1

Views: 71

Answers (2)

jwvh
jwvh

Reputation: 51271

I noticed that your code doesn't actually produce the expected result from your example input. I'm going to assume that the example given is the correct result.

def findIndices(movieRatings :String) :String = {
  val Array(movie, ratings @_*) = movieRatings.split(",", -1)
  val mx = ratings.maxOption  //Scala 2.13.x
  ratings.indices
         .filter(x => mx.contains(ratings(x)))
         .mkString(s"$movie,",",","")
}

Note that this doesn't address some of the shortcomings of your algorithm:

  • No comma allowed in movie name.
  • Only works for ratings from 0 to 9. No spaces allowed.

testing:

List("AA"
  ,"BB,"
  ,"CC,5"
  ,"DD,2,5"
  ,"EE,2,5, 9,11,5"
  ,"a,b,2,7").map(findIndices)

//res0: List[String] = List(AA,    <-no ratings
//                        , BB,0   <-comma, no ratings
//                        , CC,0   <-one rating
//                        , DD,1   <-two ratings
//                        , EE,1,4 <-" 9" and "11" under valued
//                        , a,0    <-comma in name error
//                        )

Upvotes: 0

Andronicus
Andronicus

Reputation: 26046

You can zipWithIndex and use filter:

ratings.zipWithIndex
  .filter { case(_, value) => value == max }
  .map { case(index, _) => index }

Upvotes: 1

Related Questions