Home > OS >  Stream Filter from another Stream
Stream Filter from another Stream

Time:11-03

I'm attempting to filter a Map using a stream. The predicate/condition I'm filtering by is another stream. I'm currently encountering the issue of IllegalStateException, probably because I'm accessing a stream which has already been accessed.

Map<Integer, Double> table = Map.of(10, 8.0,
                                    15, 10.0,
                                    20, 28.0,
                                    40, 40.0);

Stream<Double> streamDbl = getDoublefromInt(table, Stream.of(20, 40));

Referencing this website, I came up with something like the code segment below but it does not work.

public static Stream<Double> getDoublefromInt(Map<Integer, Double> table, Stream<Integer> id) {
 return table.entrySet().stream
        .filter(map -> id.anyMatch(id -> id.equals(map.getKey())))
        .map(map -> map.getValue());
}

CodePudding user response:

Stream is a basically an iterator over the source of data, it's not a container of data (like Collections). Once it's consumed, it can't be used anymore. For that reason, you're getting an IllegalStateException by trying to fire the same stream multiple times.

You don't need Stream IPA for what you're trying to achieve, functionality offered by the Collections framework would be sufficient for that.

All the heavy lifting can be done using Collection.retainAll().

public static Stream<Double> getDoubleFromInt(Map<Integer, Double> table, Stream<Integer> id) {
    
    Set<Integer> idSet = id.collect(Collectors.toSet());
    Map<Integer, Double> copy = new HashMap<>(table);
    
    copy.keySet().retainAll(idSet);
    
    return copy.values().stream();
}

CodePudding user response:

You can use a stream Supplier.

Demo:

import java.util.Map;
import java.util.function.Supplier;
import java.util.stream.Stream;

public class Main {
  public static void main(String[] args) {
    Map<Integer, Double> table = Map.of(
        10, 8.0,
        15, 10.0,
        20, 28.0,
        40, 40.0);

    Stream<Double> streamDbl = getDoublefromInt(table, () -> Stream.of(20, 40));

    streamDbl.forEach(System.out::println);
  }

  public static Stream<Double> getDoublefromInt(Map<Integer, Double> table, Supplier<Stream<Integer>> ids) {
    return table.entrySet().stream()
        .filter(map -> ids.get().anyMatch(id -> id.equals(map.getKey())))
        .map(map -> map.getValue());
  }
}

Output:

28.0
40.0

CodePudding user response:

I don't fully understand what it means to filter the map? If you want to get stream of values from the map that corresponds to the keys that are specified in the other stream, then the solution is simple:

public class Main {
    static Map<Integer, Double> table = Map.of(10, 8.0,
            15, 10.0,
            20, 28.0,
            40, 40.0);

    public static Stream<Double> getDoubleFromInt(Map<Integer, Double> table, Stream<Integer> id) {
        return id.map(table::get);
    }

    public static void main(String[] args) {
        getDoubleFromInt(table, Stream.of(20, 40))
                .forEach(System.out::println);
    }
}

prints

28.0
40.0

Perhaps you need to decide what to do if there is no value for the some keys, in this case there will be Null in the stream. Or you may filter out this Null values.

CodePudding user response:

BE SIMPLE!!!

Why do not you use incomming Stream?

public static Stream<Double> getDoubleFromInt(Map<Integer, Double> table,
                                              Stream<Integer> id) {
    return id.map(table::get)
             .filter(Objects::nonNull);
}

Looks like the result Stream will be the same.

  • Related