2016-06-22 3 views
2

У меня есть iterable фьючерсов, каждый из которых возвращает последовательность: Iterable[Future[Seq[Int]]] В результате мне нужна последовательность, которая представляет собой конкатенацию последовательностей, возвращаемых с фьючерса: Seq[Int].scala фьючерсы последовательное ленивое исполнение

Дело в том, что мне нужны только первые n элементы результирующей последовательности, поэтому мне не всегда нужно выполнять все фьючерсы. Я также заранее не знаю, сколько фьючерсов нужно выполнить для его достижения (возможно, первый из них вернет достаточно, возможно, нам нужно выполнить все).

Очевидно, что мне нужно выполнить мои функции последовательно. Я мог бы сделать foreach и break/return, но я хотел бы выразить это в функциональном стиле.

+1

Обратите внимание, что если у вас уже есть 'Iterable'' Future ', они уже« запущены ». –

+0

@EndeNeu ах, это очень ценный комментарий! Так, на самом деле, нет способа «отменить» их больше? –

+0

, но подождите немного, если это действительно «Итерируемый», а не 'Seq', они действительно будут запущены? Я инициализирую их «по требованию», разве это не поможет? –

ответ

2

Следующие, кажется, работают и «смотрятся» функционально. У меня недостаточно знаний о том, как это будет действовать или действовать под капотом.

Это может быть легко удалено в def, где жестко закодированный 4 передается параметр.

Я решил, что я должен вернуть 5 элементов, хотя только 4 были запрошены, так как оценка среднего будущего должна произойти в любом случае. Удаление лишних элементов должно быть простым.

val f = Iterable(Future(Seq(1,2,3)), Future(Seq(4,5)), Future(Seq(6,7,8))) 

val output = f.foldLeft(Future(Seq.empty[Int])){(previous, next) => 
    previous.flatMap{pSeq => 
     if(pSeq.length >= 4) { 
      Future(pSeq) 
     } else { 
      next.map(nSeq => pSeq ++ nSeq) 
     } 
    } 
} 

println(Await.result(output, Duration.Inf)) //List(1,2,3,4,5) 

Бит, который мне не нравится, это обертывание pSeq в будущем, чтобы поддерживать согласованные типы.

РЕДАКТИРОВАТЬ: Ответ на ответ виктора (я не могу комментировать, так как не достаточно высокий показатель репутации, и это немного меняет мой ответ).

Несмотря на то, что ответ Виктора легче читать, он должен дождаться завершения всех фьючерсов, даже если они не требуются.

Например заменить п в шахте со следующим:

val f = Iterable(Future(Seq(1,2,3)), Future(Seq(4,5)), Future(throw new Exception)) 

Это будет по-прежнему работать, звонки Виктора Future.sequence, который поворачивает итератор [Future []] Инт будущего [Iterable [] ], и поэтому все должно быть завершено.

+0

Я дам ему попробовать, спасибо –

1

Либо вы используете Future.fold:

scala> import scala.concurrent._ 

scala> import ExecutionContext.Implicits.global 

scala> Future.fold(Iterable(Future(Seq(1,2,3)), Future(Seq(4,5)), Future(Seq(6,7,8))))(Seq.empty[Int])((prev, cur) => if(prev.size >= 4) prev else prev ++ cur) foreach println 

List(1, 2, 3, 4, 5) 

scala> 

Или вы смотрите на то, как реализуется Future.fold и добавить условие выхода. (по существу, foldUntil)

+0

как прокомментировано в другом ответе, это выполнит все фьючерсы, даже если они не нужны –

Смежные вопросы