1

I have got Future<List<Directory>> dave. dave is a Future, but in the future it might change into a Stream. Therefore I think ahead and subscribe to him like this:

var daveSub = Stream<List<Directory>>
    .fromFuture(dave())
    .listen((List<Directory> folders) {
  ...
});

If dave gives me a directory with path under some /root/folder, I want to doStuff(); and cancel my subscription to dave. My current approach looks like this:

var daveSub = Stream<List<Directory>>
    .fromFuture(dave())
    .listen((List<Directory> folders) {

  for (final Directory folder in folders) {
    if (folder.path.startsWith('/root/folder')) {
      doStuff(folder);
      daveSub.cancel();
    }
  }

});

But this doesn't look right to me, especially the for cycle inside listener. Using a basic features of Future it doesn't look right as well:

dave()
    .then((List<Directory> folders) {

  for (final Directory folder in folders) {
    if (folder.path.startsWith('/root/folder')) {
      doStuff(folder);
    }
  }

});

Is there some better way to handle dave's list items (and maybe avoid the nested for cycle)?

I would expect something like this:

Stream<Directory>
    .fromFuture(dave())
    .firstItemWhere((Directory folder) => folder.path.startsWith('/root/folder'))
    .then((Directory folder) {
  doStuff(folder);
});

or this:

dave()
    .firstItemWhere(((Directory folder) => folder.path.startsWith('/root/folder')) {
  doStuff(folder);
});

or at least:

dave()
    .then((List<Directory> folders) {
  for (final Directory folder in folders if folder.path.startsWith('/root/folder')) {
    doStuff(folder);
  }
});
aleskva
  • 1,023
  • 1
  • 13
  • 30
  • Does it answer your question https://stackoverflow.com/questions/42611880/difference-between-await-for-and-listen-in-dart ? – Antonin GAVREL Feb 27 '21 at 17:18
  • I know about this, but I'm not sure how it could help me to make things better in this case – aleskva Feb 27 '21 at 17:27
  • 1
    Toy may want to change the `Stream>` to a `Stream`, perhaps by `var stream = future.asStream().expand((x)=>x);`. Then you get one element at a type instead of just one list of the elements. Then the `firstWhere` should work. – lrn Mar 01 '21 at 08:52
  • Cool! Is it a good strategy to use expand() ? – aleskva Mar 01 '21 at 15:21
  • Does expand have any advantage over for loop? – aleskva Mar 06 '21 at 16:55

3 Answers3

1

You can just use a break clause to exit your loop when you find the right one:

var daveSub = Stream<List<Directory>>
    .fromFuture(dave())
    .listen((List<Directory> folders) {

  for (final Directory folder in folders) {
    if (folder.path.startsWith('/root/folder')) {
      doStuff(folder);
      break;
    }
  }
   daveSub.cancel();

});

What is wrong with the loop inside the listener?

Antonin GAVREL
  • 5,674
  • 3
  • 22
  • 44
0

You should just be able to find the item you are looking for without even having to handle a subscription, take a look at this example:

void main() async {
 var stream = Stream.fromIterable([[1,2,3],[4,5,6],[7,8,9]]);
  var item = await stream.expand((e) => e)
               .firstWhere((e) => e == 3, orElse: () => null);
  
  if (item != null) {
     // Do stuff 
  }
}

Mattia
  • 3,771
  • 1
  • 19
  • 36
  • Can I insert Future> into Future.value() ? – aleskva Feb 27 '21 at 18:07
  • You can insert whatever type you want, that was just an example and btw using either `Future.asStream` or `Stream.fromFuture` has no difference afaik – Mattia Feb 27 '21 at 21:55
  • It doesn't work for me, your example returns me the whole List, not a single item – aleskva Feb 27 '21 at 22:25
  • You must have an error in your code, please share what you have done. – Mattia Feb 27 '21 at 22:57
  • I copied your code and inserted print(item); into the if. I found out there is no `e` because the only `e` it got is `[1,2,3,4,5]` which is != 3. Also the only item I could get was `[1,2,3,4,5]` – aleskva Mar 01 '21 at 15:16
  • I'm sorry, now it should work properly, I edited the code to better reflect your structure. Please try it out – Mattia Mar 01 '21 at 20:19
  • Now it's just the same as @lrm mentioned above. Anyway it sums what I'm looking for. – aleskva Mar 01 '21 at 23:01
  • Does expand have any advantage over for loop? – aleskva Mar 06 '21 at 16:55
0

As @lrn suggested, expand() is what I was looking for. Similar stream then looks like this:

Stream<List<Directory>>.fromFuture(dave())
                .expand((List<Directory> _folders) => _folders)
                .listen((Directory _folder) {
                  doStuff();
                });
aleskva
  • 1,023
  • 1
  • 13
  • 30