Свернуть список параметров, чтобы найти первый или последний - PullRequest
7 голосов
/ 07 ноября 2011

Я пытаюсь свернуть список опций, чтобы вернуть первое (или последнее) значение Some или None, если некоторые значения отсутствуют.

scala> val opts = List(None, Some(1), None, Some(2), None)
opts: List[Option[Int]] = List(None, Some(1), None, Some(2), None)

scala> opts foldLeft(None)((a,io) => a match { case None => io; case Some(i) =>
a})
<console>:9: error: object None does not take parameters
              opts foldLeft(None)((a,io) => a match { case None => io; case Some
(i) => a})
                                 ^

Не уверен, что я делаю не так. Также, вероятно, есть способ сделать это проще, используя функцию более высокого порядка, но ничего из здесь не бросилось в глаза.

Ответы [ 5 ]

14 голосов
/ 07 ноября 2011

Может быть, это может решить вашу проблему - первый элемент:

opts.flatten.headOption

И последний элемент:

opts.flatten.lastOption

flatten метод распакует все Option значения всписок и отбросить все None значений.headOption / lastOption вернет либо Some для первого / последнего элемента в списке, либо None, если список пуст.

9 голосов
/ 07 ноября 2011

ответ Тенши довольно прост, но для длинных списков он попытается сгладить все, что не лень. (Я думаю, что view нам здесь тоже не поможет, но я не совсем уверен.)

В этом случае вы можете использовать:

opts.dropWhile(_.isEmpty).headOption.flatMap(identity)

К сожалению, мы не можем использовать flatten здесь, так как это вернет универсальный Iterable[Int] и не Option, поэтому мы должны выбрать более длинную идиому flatMap(identity).

Редактировать: Как Дэйв заметил:

opts.find(_.isDefined).flatMap(identity)

было бы еще лучше.

4 голосов
/ 07 ноября 2011

Есть лучшие способы сделать это, но чтобы ответить на поставленный вопрос, у вас есть две проблемы

1) Вам не хватает . после opts.Вы можете использовать только инфиксную нотацию для преобразования a.m(b) в a m b.Метод foldLeft имеет вид a.m(b)(c).Так что или напишите это так, или включите скобки (a m b)(c).

2) Вам необходимо параметризовать None как Option[Int]: здесь он интерпретируется как объект None, а не как значениеOption[Int] экземпляра.

Так что это будет работать:

opts.foldLeft(None: Option[Int])(
  (a,io) => a match { case None => io; case Some(i) => a } )
2 голосов
/ 07 ноября 2011

Зачем идти на такие неприятности?

opts.find(_.nonEmpty).flatten
opts.reverse.find(_.nonEmpty).flatten
0 голосов
/ 29 марта 2019

Начиная с Scala 2.9, вы можете использовать collectFirst для извлечения первой определенной опции:

List(None, Some(1), None, Some(2), None).collectFirst { case Some(x) => x }
// Option[Int] = Some(1)

это прекратит итерацию на первом определенном Option и позволит избежать сглаживания целого List перед поиском его головы.


Начиная с Scala 2.13 вы можете использовать findLast, что противоположно find (в ожидании возможного collectLast?)

List(None, Some(1), None, Some(2), None).findLast(_.isDefined).flatten
// Option[Int] = Some(2)
...