Scala возвращается на первый список в списке
-
30-09-2019 - |
Вопрос
У меня есть список 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
с LazyList
S, это станет:
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
покажет разные показатели - большинство будет хуже.)