14

基于索引位置仅遍历Scala中集合的奇数成员的有效方法是什么?

鉴于此列表:

val fruits: List[String] = List("apples", "oranges", "pears", "bananas")

我想跳过苹果和梨,加工橙子和香蕉。谢谢!

根据给出的回复进行更新:

哇,前三个答案中的每一个都有优点。从 Scala Collections 语法的角度来看,我最初的意思是“高效”这个词,而我实际上只是在寻找一种巧妙的方法来为后续迭代创建子列表。@Senia 很好地介绍了sliding() 函数,非常适合这个特定的用例,但我也喜欢@Brian 使用 zipWithIndex() 的更通用的方法。

但是,当我考虑到最初提出的问题的实际措辞和@sourcedelica 响应的计算效率时,我认为他会因此而获奖。

4

7 回答 7

18
scala> List("apples", "oranges", "pears", "bananas").drop(1).sliding(1, 2).flatten.toList
res0: List[java.lang.String] = List(oranges, bananas)
于 2012-10-08T04:32:23.723 回答
17
val fruits: List[String] = List("apples", "oranges", "pears", "bananas")

fruits.zipWithIndex.filter(_._2 % 2 == 1).map(_._1)

res0: List[String] = List(oranges, bananas)

zipWithIndex 将 List 中的每个元素与一个索引配对,给出:

List[(String, Int)] = List((apples,0), (oranges,1), (pears,2), (bananas,3))

过滤奇数元素filter(_._2 % 2 == 1)

List[(String, Int)] = List((oranges,1), (bananas,3))

将 List[(String, Int)] 映射到 List[String] 通过获取每个元组的第一个元素并.map(_._1)给出:

List[String] = List(oranges, bananas)

于 2012-10-08T04:52:06.993 回答
7

这是一种直接迭代奇数的方法:

val fruits: List[String] = List("apples", "oranges", "pears", "bananas")
//> fruits  : List[String] = List(apples, oranges, pears, bananas)

val oddFruitsIterator = 
  Iterator.from(1, 2).takeWhile(_ < fruits.size).map(fruits(_))
//> oddFruits  : Iterator[String] = non-empty iterator

oddFruitsIterator.foreach(println)                      
//> oranges
//> bananas

如果它是一个大型集合和/或您正在进行大量迭代,那么您将需要考虑将其转换为IndexedSeq第一个集合,因此它fruits(_)是 O(1)。例如:

val fruitsIs = fruits.toIndexedSeq
val oddFruits = Iterator.from(1, 2).takeWhile(_ < fruitsIs.size).map(fruitsIs(_))

请注意,迭代器本身与它正在迭代的集合是分开的。这是另一个更清楚的例子:

scala> val oddSeqIterator = 
   (seq: Seq[String]) => Iterator.from(1, 2).takeWhile(_ < seq.size).map(seq(_))
oddSeqIterator: Seq[String] => Iterator[String] = <function1>

scala> val fruits: List[String] = List("apples", "oranges", "pears", "bananas")
fruits: List[String] = List(apples, oranges, pears, bananas)

scala> oddSeqIterator(fruits)
res0: Iterator[String] = non-empty iterator

scala> res0.foreach(println)
oranges
bananas
于 2012-10-08T15:59:39.543 回答
1

我会提出另一种方法,使用递归,在我看来,这似乎使操作尽可能少,即使它不如其他解决方案那么花哨。

def iterateOdd(myList:List[String]):List[String] = myList match{
  case _::odd::tail => odd::iterateOdd(tail)
  case _ => Nil
}

或者,如果您只想处理奇数成员

def iterateOdd(myList:List[String]):Unit = myList match{
  case _::odd::tail => println(odd); iterateOdd(tail)
  case _ =>   
}
于 2012-10-08T12:52:15.310 回答
0

还有另一种选择,基于List::grouped以成对对项目进行分区(这提供了一种在奇数位置访问项目的简单方法)和Iterator::collect为了处理奇数长度的集合的组合:

// val fruits = List("apples", "oranges", "pears", "bananas", "tomatoes")
fruits.grouped(2).collect { case a :: b => b }.toList
// List("oranges", "bananas")
于 2019-01-20T18:20:32.883 回答
0

我认为 tailrec 会是一个更好的选择,因为 id 不需要任何堆栈并且它是 O(1):

def f(arr:List[Int]):List[Int] = {
@tailrec
  def loop(source:List[Int],destination:List[Int]):List[Int]= source match {
    case _::odd::tail => loop(tail,destination :+ odd)
    case _ => destination
  }
  loop(arr,List())
}
于 2021-10-18T14:33:10.400 回答
-1
  • 我有另一种方法来解决这类问题。
  • 我们可以利用 List.range(start,end) 方法。

List.range(0,5) 将给出 List(0,1,2,3,4)

  • 我们可以生成索引列表,我们可以过滤它们

    scala> val fruits: List[String] = List("apples", "oranges", "pears", "bananas")

    scala> List.range(0,fruits.length).filter(_%2!=0).map(x=>fruits(x))

    res0: List[String] = List(橙子、香蕉)

于 2018-02-03T16:53:22.217 回答