Перейдем через нечетные элементы коллекции в Scala

Каков эффективный способ итерации только с нечетными членами коллекции в Scala на основе позиции индекса?

Учитывая этот список:

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

Я хочу пропустить яблоки и груши, а также обработать апельсины и бананы. Спасибо!

Обновление на основе полученных ответов:

Ничего себе, каждый из трех лучших ответов заслуживает внимания. Первоначально я имел в виду слово "эффективный" из синтаксиса Scala Collections, и я действительно просто искал способ создания подсписчика для последующей итерации. @Senia отлично справляется с функцией slide(), отлично подходит для этого конкретного случая использования, но мне также нравится @Brian более обобщенный подход с использованием zipWithIndex().

Однако, когда я рассматриваю фактическую формулировку вопроса, как было первоначально задано, и вычислительную эффективность ответа @sourcedelica, я думаю, что он получает приз за это.

Ответ 1

Вот способ прямого перебора нечетных:

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

Ответ 2

scala> List("apples", "oranges", "pears", "bananas").drop(1).sliding(1, 2).flatten.toList
res0: List[java.lang.String] = List(oranges, bananas)

Ответ 3

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)

Ответ 4

Я бы предложил другой метод, используя рекурсию, которая, по-моему, делает как можно меньше операций, даже если она менее интересна, чем другие решения.

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 _ =>   
}

Ответ 5

Еще одна альтернатива, основанная на комбинации List::grouped для разделения элементов по парам (что обеспечивает простой способ доступа к элементам при нечетных возможностях) и Iterator::collect для обработки коллекций с нечетной длиной:

// val fruits = List("apples", "oranges", "pears", "bananas", "tomatoes")
fruits.grouped(2).collect { case a :: b => b }.toList
// List("oranges", "bananas")

Ответ 6

  • У меня есть другой подход к решению этой проблемы.
  • Мы можем использовать метод List.range(начало, конец).

List.range(0,5) предоставит List (0,1,2,3,4)

  • Мы можем сгенерировать список индексов, и мы можем их фильтровать

    scala > val fruits: List [String] = Список ( "яблоки", "апельсины", "груши", "бананы" )

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

    res0: Список [String] = Список (апельсины, бананы)