How to return multiple items from a list, given their indices?

落爺英雄遲暮 提交于 2019-12-07 18:00:31

问题


Let's say, I have a list. If I want to return something at the index of that list, I can just pass the lists' val, the index. Like so.

val list = List(1, 2, 3) 
list(0) //Int = 1

But what if I want items at multiple indexes on this list? I want to be able to do this... list(0, 1) and get a collection of the items at those indices.

This is crazily simple in Ruby. Anyone have any suggestions?


回答1:


You can flip the logic around, so that for each index, you're getting the index, you retrieve the element at that index. Since you are using the apply method on List, there are several shorthand expressions of this logic:

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

It's worth noting that since these are all maps on indices, the resulting collection will generally have the same type as indices, and not list:

val list = Array(1, 2, 3)
val indices = List(0, 1)
indices map list //List(1, 2), instead of Array(1, 2)

This can be an undesirable property here. One solution to this is to use breakOut (in scala.collection):

val newList: Array[Int] = indices.map(list)(breakOut)

You can read more about breakOut here. The following solutions also maintain the collection type of list when possible by performing operations on list instead of indeces:

If you are looking for a contiguous range of the list, you might consider using slice:

list.slice(1, 2) //List(2)

You could also use drop and take (and the dropRight, takeRight versions) to a similar effect:

list.drop(1).take(1)

For more complex versions of this type of filtering, you might be interested in the zipWithIndex method, which would allow you to express arbitrary logic on the index:

list.zipWithIndex.collect { 
    case(el, index) if indices.contains(index) /* any other logic */ => el 
}



回答2:


The answer from @Ben is spot on.

However, if you want to be able to use the syntax you describe list(0, 1), then Scala allows you to do that through implicit conversions:

implicit class MultiIndexList[A](list: List[A]){
    def apply(indices: Int *) = indices.map(list)
}

Assuming you are working on the 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)



回答3:


If you are looking for an equivalent to Ruby's Array#slice (aka Array#[]) method, there are two:

  • the equivalent to Ruby's Array#[](index) is, as you mentioned, List.apply(n: Int): A
  • the equivalent to Ruby's Array#[](range) is List.slice(from: Int, until: Int): List[A]
  • there is no equivalent to Ruby's Array#[](start, length)

There is also no equivalent to Ruby's Array#values_at.



来源:https://stackoverflow.com/questions/30878607/how-to-return-multiple-items-from-a-list-given-their-indices

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!