Filter list by index?
val data = List("foo", "bar", "bash") val selection = List(0, 2) val selectedData = data.filter(datum => selection.contains(datum.MYINDEX)) // INVALID CODE HERE ^ // selectedData: List("foo", "bash") Say I want to filter out a List selected indexes. If in the filter method I could refer to the index of the list item, then I could solve it as indicated above, but datum.MYINDEX not valid in the above case.
How can i do this?
It is not recommended to do it differently (although it may be slower in lists, since indexing is slow (O (n)). Vectors will be better. On the other hand, contains another solution for each element in data not exactly fast)
val data = List("foo", "bar", "bash") //> data : List[String] = List(foo, bar, bash) val selection = List(0, 2) //> selection : List[Int] = List(0, 2) selection.map(index=>data(index)) //> res0: List[String] = List(foo, bash) The first solution that occurred to me was to create a list of pairs (element, index), filter each element, checking if the selection contains this index, and then display the resulting list to save only raw elementd (omit the index) . The code itself explains:
data.zipWithIndex.filter(pair => selection.contains(pair._2)).map(_._1) or more readable:
val elemsWithIndices = data.zipWithIndex val filteredPairs = elemsWithIndices.filter(pair => selection.contains(pair._2)) val selectedElements = filteredPairs.map(_._1) Since you already have a list of indexes, the most effective way is to directly select these indexes:
val data = List("foo", "bar", "bash") val selection = List(0, 2) val selectedData = selection.map(index => data(index)) or even:
val selectedData = selection.map(data) or if you need to keep the order of the elements in the data:
val selectedData = selection.sorted.map(data) UPDATED
In the spirit of searching for all possible algorithms, here is the version using collect :
val selectedData = data .zipWithIndex .collect { case (item, index) if selection.contains(index) => item } The following is probably the most scalable way to do this in terms of efficiency, and unlike many answers to SO, it actually follows the official scala style guide.
import scala.collection.immutable.HashSet val selectionSet = new HashSet() ++ selection data.zipWithIndex.collect { case (datum, index) if selectionSet.contains(index) => datum } If the resulting set should be passed to additional flatMap , flatMap , etc., suggest turning data into a lazy sequence. Actually, perhaps you should do this anyway to avoid 2 passes, one for zipWithIndex for collect , but I doubt that with comparative testing you will get a lot.