-2

There is Data Set<Long> input and Map<Long, List<String>> store.

And I wanna get List only 10 size.

Map<Long, List<String>> datas = {...{;
Set<Long> input = {....};
List<String> output = new ArrayList<>();

for(Long key : input) {
    if(output.size() >= 10) break;
    List<String> tmp = datas.get(key);
    for(String val : tmp) {
        if(output.size() >= 10) break;
        output.add(val);
    }
}

I can't use java 9 doWhile in stream

ernest_k
  • 44,416
  • 5
  • 53
  • 99
EdgarHan
  • 85
  • 1
  • 1
  • 10

1 Answers1

2

A corresponding stream pipeline can be

List<String> output = input.stream()
    .flatMap(i -> datas.get(i).stream()).limit(10)
    .collect(Collectors.toList());

Test:

Map<Long, List<String>> datas = new HashMap<>();
datas.put(1l, Arrays.asList("a", "b", "c", "d", "e", "f", "g"));
datas.put(2l, Arrays.asList("z", "y", "x", "w", "v", "u", "t"));
Set<Long> input = new LinkedHashSet<>(Arrays.asList(1l, 2l, 3l, 4l, 5l));

System.out.println(input.stream()
        .flatMap(i -> datas.get(i).stream()).limit(10)
        .collect(Collectors.toList()));

And that prints [a, b, c, d, e, f, g, z, y, x]

ernest_k
  • 44,416
  • 5
  • 53
  • 99
  • If write like this, can loop 10000 times to get just 10 sizes List? – EdgarHan Feb 26 '21 at 01:41
  • @EdgarHan It doesn't. `limit(10)` will stop it. Test the code (or add `.peek(System.out::println)` before `collect` to see what keys were looked up. And this code would throw a nullpointerexception if all keys from `input` were looked up. – ernest_k Feb 26 '21 at 01:44
  • Before `.peek(System.out::println)` `limit(10)` loop exec 10 or more times it is right? – EdgarHan Feb 26 '21 at 02:09
  • `limit(10)` is run on the stream of inner list elements. But the important thing is that `datas.get(i)` is only executed twice in the above code. What happens is that the list for `1l` will be passed to limit, then the list for `2l`. `limit()` will get to `10` while processing elements from the second list. When 10 is reached, there will be no more `datas.get(i)` calls. And a way to confirm that is by seeing that `datas.get(3l).stream()` would throw an NPE as there is no value for 3l in the map; but that exception is not raised by this code. – ernest_k Feb 26 '21 at 02:18
  • If `2l` value list size is 100000. Then, exec for loop 100000 times, and collecting 10 size List from 100007 size stream, It is right?? – EdgarHan Feb 26 '21 at 02:27
  • `flatMap` will send one element at a time to `limit`, if I can put it that way. And `limit` won't see the 11th value, because it will tell `flatMap` to stop as soon as the 10th element has been received. If you put `.peek(System.out::println)` **before** `limit(10)`, you'll see that it doesn't print `"w"` from the example above. I hope I understand your query. – ernest_k Feb 26 '21 at 02:33
  • 1
    @ernest_k it may or may not see `"w"`, that’s an implementation detail. With Java 8 before update 222, as well as Java 9, the `peek` before `limit` will even see `"v"`, `"u"`, and `"t"`. See [this Q&A](https://stackoverflow.com/q/29229373/2711488). With a parallel stream, even the exceptions due to calling `stream()` on `null` may occur. It’s not a good idea to rely on the laziness… – Holger Feb 26 '21 at 09:07
  • @Holger Yes, thanks. Something was scratching me as I wrote that. I think I've seen that post about flatMap's problematic behavior when combined with limit or short-circuiting terminal operations. I'll ignore the NPE risk for now as it's not part of the question, but yes, it shouldn't be assumed. – ernest_k Feb 26 '21 at 09:25
  • 2
    Yes that’s only an issue of the example program; for the OP’s task, the approach is sufficient. – Holger Feb 26 '21 at 09:49