Вопрос

У меня есть список l:List[T1] И в настоящее время я выполняю следующее:

myfun : T1 -> Option[T2]
val x: Option[T2] = l.map{ myfun(l) }.flatten.find(_=>true)

То myfun Функция не возвращает ни один или некоторые, сплющины бросают все ничего не и находят, возвращает первый элемент списка, если таковые имеются.

Это кажется мне немного взлом. Я думаю, что может существовать некоторое понимание или аналогичное, что сделает это немного менее расточительным или умным. Например: мне не нужны последующие ответы, если myfun возвращается Любые Some в течение map из списка l.

Это было полезно?

Решение

Как насчет:

l.toStream flatMap (myfun andThen (_.toList)) headOption

Поток ленивый, поэтому он не будет отображаться все заранее, но он также не будет перенасматривать вещи. Вместо выравнивания вещей, конвертировать Option к List так что flatMap может быть использован.

Другие советы

Ну, это почти, но не совсем

val x = (l flatMap myfun).headOption

Но вы возвращаете Option а не а. List От MyFun, так что это может не работать. Если это так (я не передачу в руку), то попробуйте вместо этого:

val x = (l flatMap(myfun(_).toList)).headOption

В дополнение к использованию toStream сделать поиск ленивый, мы можем использовать Stream::collectFirst:

List(1, 2, 3, 4, 5, 6, 7, 8).toStream.map(myfun).collectFirst { case Some(d) => d }
// Option[String] = Some(hello)
// given def function(i: Int): Option[String] = if (i == 5) Some("hello") else None

Этот:

  • Преобразует List в а Stream Для того, чтобы остановить поиск рано.

  • Преобразует элементы с использованием myFun так как Option[T]с.

  • Собирает первый сопоставленный элемент, который не None и извлечь его.

Запуск Scala 2.13, с обесценением Streamс LazyListS, это станет:

List(1, 2, 3, 4, 5, 6, 7, 8).to(LazyList).map(function).collectFirst { case Some(d) => d }

Ну, эквивалент для понимания довольно легко

(for(x<-l, y<-myfun(x)) yield y).headOption

Что, если вы на самом деле сделаете перевод, работает так же, как дал oxbow_Lakes. Предполагая, что разумная лень списка .flatmap, это как чистое и эффективное решение.

По состоянию на 2017 год предыдущие ответы, кажется, устарели. Я бежал несколько тестов (список из 10 миллионов INT, первый матч примерно в середине, SCALA 2.12.3, Java 1.8.0, 1,8 ГГц Intel Core I5). Если иное не отмечено, list а также map иметь следующие типы:

list: scala.collection.immutable.List
map: A => Option[B]

Просто позвоните map В списке: ~ 1000 мс

list.map(map).find(_.isDefined).flatten

Первый звонок toStream В списке: ~ 1200 мс

list.toStream.map(map).find(_.isDefined).flatten

Вызов toStream.flatMap В списке: ~ 450 мс

list.toStream.flatMap(map(_).toList).headOption

Вызов flatMap В списке: ~ 100 мс

list.flatMap(map(_).toList).headOption

Первый звонок iterator В списке: ~ 35 мс

list.iterator.map(map).find(_.isDefined).flatten

Рекурсивная функция find(): ~ 25 мс

def find[A,B](list: scala.collection.immutable.List[A], map: A => Option[B]) : Option[B] = {
  list match {
    case Nil => None
    case head::tail => map(head) match {
      case None => find(tail, map)
      case result @ Some(_) => result
    }
  }
}

Итеративная функция find(): ~ 25 мс

def find[A,B](list: scala.collection.immutable.List[A], map: A => Option[B]) : Option[B] = {
  for (elem <- list) {
    val result = map(elem)
    if (result.isDefined) return result
  }
  return None
}

Вы можете еще больше ускорить вещи, используя Java вместо Scala Collections и менее функциональный стиль.

Петля по индексам в java.util.ArrayList: ~ 15 мс

def find[A,B](list: java.util.ArrayList[A], map: A => Option[B]) : Option[B] = {
  var i = 0
  while (i < list.size()) {
    val result = map(list.get(i))
    if (result.isDefined) return result
    i += 1
  }
  return None
}

Петля по индексам в java.util.ArrayList с функцией возврата null вместо None: ~ 10 мс

def find[A,B](list: java.util.ArrayList[A], map: A => B) : Option[B] = {
  var i = 0
  while (i < list.size()) {
    val result = map(list.get(i))
    if (result != null) return Some(result)
    i += 1
  }
  return None
}

(Конечно, обычно обычно объявляет тип параметра как java.util.List, нет java.util.ArrayList. Отказ Я выбрал последнее здесь, потому что это класс, который я использовал для ориентиров. Другие реализации java.util.List покажет разные показатели - большинство будет хуже.)

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top