按项目索引过滤列表?

时间:2014-09-02 19:02:00

标签: scala

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")

假设我想在给定选定索引列表的情况下过滤List。如果在filter方法中,我可以引用列表项的索引,那么我可以像上面那样解决这个问题,但datum.MYINDEX在上述情况下无效。

我怎么能这样做呢?

7 个答案:

答案 0 :(得分:7)

如何使用zipWithIndex来保留对项目索引的引用,如此过滤,然后将索引映射掉?

data.zipWithIndex
    .filter{ case (datum, index) => selection.contains(index) }
    .map(_._1)

答案 1 :(得分:1)

从另一个角度来做这件事比较简洁(虽然索引可能很慢,因为索引很慢(O(n))。向量会更好。另一方面,containsdata中每个项目的另一个解决方案并不是非常快“

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)

答案 2 :(得分:0)

我想到的第一个解决方案是创建一个对列表(元素,索引),通过检查选择是否包含该索引来过滤每个元素,然后映射结果列表以便仅保留原始元素(省略索引)。代码是自我解释的:

data.zipWithIndex.filter(pair => selection.contains(pair._2)).map(_._1)

或更具可读性:

val elemsWithIndices = data.zipWithIndex
val filteredPairs = elemsWithIndices.filter(pair => selection.contains(pair._2))
val selectedElements = filteredPairs.map(_._1)

答案 3 :(得分:0)

由于您已经有一个索引列表,最有效的方法是直接选择这些索引:

val data = List("foo", "bar", "bash")
val selection = List(0, 2)
val selectedData = selection.map(index => data(index))

甚至:

val selectedData = selection.map(data)

或者如果您需要保留数据中项目的顺序:

val selectedData = selection.sorted.map(data)

<强>已更新

本着寻找所有可能算法的精神,这里使用collect的版本:

val selectedData = data
  .zipWithIndex
  .collect { 
    case (item, index) if selection.contains(index) => item 
   }

答案 4 :(得分:0)

本作品:

val data = List("foo", "bar", "bash")
val selection = List(0, 2)
val selectedData = data.filter(datum => selection.contains(data.indexOf(datum)))
println (selectedData)

输出: 列表(foo,bash)

答案 5 :(得分:0)

以下是在效率方面可能最具扩展性的方式,与SO上的许多答案不同,它实际上完全遵循官方的scala风格指南。

import scala.collection.immutable.HashSet

val selectionSet = new HashSet() ++ selection

data.zipWithIndex.collect { 
  case (datum, index) if selectionSet.contains(index) => datum
}

如果要将结果集合传递给其他mapflatMap等,建议将data转换为延迟序列。实际上也许你应该这样做,以避免2遍,zipWithIndex collect一个,但我怀疑基准时会有多少收获。

答案 6 :(得分:0)

实际上有一种更简单的方法可以使用map方法按索引进行过滤。这是一个例子

val indices = List(0, 2)
val data = List("a", "b", "c")

println(indices.map(data)) // will print List("a", "c")