【发布时间】:2016-07-13 01:30:51
【问题描述】:
假设,我有一个清单。如果我想在该列表的索引处返回某些内容,我可以传递列表的 val,即索引。像这样。
val list = List(1, 2, 3)
list(0) //Int = 1
但是,如果我想要此列表中多个索引处的项目怎么办?我希望能够做到这一点...list(0, 1) 并获取这些索引处的项目集合。
这在 Ruby 中非常简单。有人有什么建议吗?
【问题讨论】:
假设,我有一个清单。如果我想在该列表的索引处返回某些内容,我可以传递列表的 val,即索引。像这样。
val list = List(1, 2, 3)
list(0) //Int = 1
但是,如果我想要此列表中多个索引处的项目怎么办?我希望能够做到这一点...list(0, 1) 并获取这些索引处的项目集合。
这在 Ruby 中非常简单。有人有什么建议吗?
【问题讨论】:
您可以翻转逻辑,以便为每个索引获取索引,然后检索该索引处的元素。由于您在List 上使用了apply 方法,因此该逻辑有几个速记表达式:
val indices = List(0, 1)
indices.map(index => list.apply(index))
indices.map(index => list(index))
indices.map(list(_))
indices.map(list)
indices map list
值得注意的是,由于这些都是maps on indices,因此生成的集合通常与indices具有相同的类型,而不是list:
val list = Array(1, 2, 3)
val indices = List(0, 1)
indices map list //List(1, 2), instead of Array(1, 2)
这可能是一个不受欢迎的属性。一种解决方案是使用breakOut(在scala.collection):
val newList: Array[Int] = indices.map(list)(breakOut)
您可以阅读有关 breakOut here 的更多信息。以下解决方案还通过对list 而不是indeces 执行操作,尽可能保持list 的集合类型:
如果您正在寻找列表的连续范围,您可以考虑使用slice:
list.slice(1, 2) //List(2)
您也可以使用drop 和take(以及dropRight、takeRight 版本)达到类似的效果:
list.drop(1).take(1)
对于此类过滤的更复杂版本,您可能对zipWithIndex 方法感兴趣,它允许您在索引上表达任意逻辑:
list.zipWithIndex.collect {
case(el, index) if indices.contains(index) /* any other logic */ => el
}
【讨论】:
indeces map list`会做的。
indeces.map(list) 可能会因为通用变量名称而被混淆。一旦你习惯了函数式编程,positions.map(itemByPosition) 就会变得可读性极强。
@Ben 的回答很到位。
但是,如果您希望能够使用您描述的语法 list(0, 1),那么 Scala 允许您通过隐式转换来做到这一点:
implicit class MultiIndexList[A](list: List[A]){
def apply(indices: Int *) = indices.map(list)
}
假设您正在处理 REPL:
val list = List(1,2,3)
list(1,2)
res1: Seq[Int] = ArrayBuffer(2, 3)
list(0,2)
res2: Seq[Int] = ArrayBuffer(1, 3)
【讨论】:
如果您正在寻找与 Ruby 的 Array#slice(又名 Array#[])方法等效的方法,则有两种:
Array#[](index) 是 List.apply(n: Int): A
Array#[](range)是List.slice(from: Int, until: Int): List[A]
Array#[](start, length)
也没有与 Ruby 的 Array#values_at 等效的东西。
【讨论】:
Array#[](start, length) 做了什么seq.drop(start).take(length) 可能会做到。