Mullefa
Mullefa

Reputation: 1247

Scala: defining a map via a list of integers

Coming to Scala from R (complete newbie).

Say I have two lists:

val index  = List(0,0,1,0,1)
val a      = List(1,2,3,4,5)

Then index can define a natural map from a to b: List[List[Int]]:

1 -> b(0)
2 -> b(0)
3 -> b(1)
4 -> b(0)
5 -> b(1)

So that:

b = List(List(1,2,4), List(3,5))

In general, given index and a, what is the most natural way to create b in Scala?

e.g. in R I could for example write:

run_map <- function(index, a) {
  map <- function(data, i) {
    data[[i]] <- a[which(index == i)]
    data
  }
  Reduce(map, unique(index), list())
}

Cheers for any help!

Upvotes: 2

Views: 503

Answers (2)

yǝsʞǝla
yǝsʞǝla

Reputation: 16422

0) Given:

val index  = List(0,0,1,0,1)
val a      = List(1,2,3,4,5)

Here is an "iterative" way to arrive at the solution:

1) "Zip" 2 lists together to produce a list of pairs:

index.zip(a)

result:

List[(Int, Int)] = List((0,1), (0,2), (1,3), (0,4), (1,5))

2) Group by first element of the pair in the list.

index.zip(a).groupBy(_._1)

result:

Map[Int,List[(Int, Int)]] = Map(1 -> List((1,3), (1,5)), 0 -> List((0,1), (0,2), (0,4)))

3) Remove redundant index by projecting only second element from each pair in the list v:

index.zip(a).groupBy(_._1).map{ case (i, v) => (i, v.map(_._2)) }

result:

Map[Int,List[Int]] = Map(1 -> List(3, 5), 0 -> List(1, 2, 4))

Upvotes: 4

wheaties
wheaties

Reputation: 35990

If you want one list to contain the index and the other list to contain the values then you would zip them together:

val myMap = (a zip b).toMap

where a contains the index and b the values.

However, if there's duplicate indexes then you would want to do the following:

for{
  (i, list) <- (a zip b) groupBy (_._1)
} yield (i, list map (_._2))

wherein you're zipping, grouping by the index and then mapping over the values in the list. That created list contains both the index and value as a tuple.

Upvotes: 4

Related Questions