Reputation: 8866
How do I filter list by indexes stored in another list? For instance I have the following list of values:
val list = List("a", "b", "c", "d", "e", "f")
and the list of indexes:
val indexes = List(1,2,5)
I want to get the following list:
List("b", "c", "f)
What is the most idiomatic way?
Upvotes: 2
Views: 2531
Reputation: 20435
Using a for comprehension as follows,
for ( (v,i) <- list.zipWithIndex if indexes.contains(i) ) yield v
Using foldLeft
as follows,
indexes.foldLeft(List[String]())( (xs,i) => xs :+ list(i) )
Upvotes: 0
Reputation: 81
To avoid creating too many intermediary objects, you could write
indexes.map(list.lift).flatten
With an indexed sequence, lookup time in the list would be constant. It's both idiomatic and efficient. If list is of type List, which has lookup time is O(n), then the you have O(m * n), where m is the length of indexes, and n is the length of the list.
The difference between this and indexes.map(list)
is whether or not you want to throw an exception if an index is not found in the list.
list.lift creates a function that takes an index and returns Some(value) if it exists, and None otherwise. The flatten
method flattens the resulting List of Option. It removes all the None results, and extracts the values from the Some results.
Upvotes: 6
Reputation: 7162
You can do just:
indexes.map(list)
which is short for
indexes.map(index => list.apply(index))
Though, I would recommend to use something that is optimized for indexes (IndexedSeq).
Upvotes: 5
Reputation: 10428
Use zipWithIndex
to add the indexes to the first list:
val l = List("a", "b", "c", "d", "e", "f").zipWithIndex
Probably better to represent the allowed indexes as a Set:
val indexes = Set(1, 2, 5)
Then simply filter based on membership of the Set and map back to the original Strings:
l.filter(tuple => indexes.contains(tuple._2)).map(_._1)
Upvotes: 2