Перейдем через нечетные элементы коллекции в 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] = Список (апельсины, бананы)