Combine List of streams into one single stream - java

I have a List<Stream<String>> that I get by doing a series of transactions.
The list size is dynamic (Maximum 3 elements) so I can't do:
Stream<String> finalStream = Stream.concat(list.get(0),Stream.concat(list.get(1),list.get(2));
I need to concatenate the list of Streams into one single Stream<String>.
Is there any simple way to do this?

If you have a list of lists, or a stream of streams, or any collection of collections, you can use flatMap to, well, flatten them. flatMap applies a mapping function which must return a stream to an input and streams each element of the result of the mapping function.
In your case, you could do:
var finalStream = list.stream().flatMap(x -> x);
x -> x is the identify function which returns the input unmodified. If you prefer, you can replace it with the expression Function.identity().

Related

java 8 double findFirst on stream

I have a HashMap that contains a single value which is an ArrayList that also contains a single value as well. I need to extract the single value from the ArrayList. At the moment I'm doing it like this:
map.values()
.stream()
.findFirst()
.orElse(new ArrayList<>()).stream().findFirst().orElse(null)
This works, but I hope for a more elegant way to get the first element of a stream inside the first element of a stream.
In other words, I want eliminate the double stream().findFirst().
Is that possible?

Stream flatMap vs map

To filter a List we can use
a1.stream().filter(x->x>6).forEach(System.out::println);
and to filter two lists I used FlatMap
Stream<List<Integer>> s2=Stream.of(a1,a2);
s2.flatMap(x->x.stream()).sorted().filter(x->x>6).forEach(System.out::println);
but I tried filtering in this way for a single List
Stream<List<Integer>> s1=Stream.of(a1);
s1.map(x->x.stream()).filter(x->x>2).forEach(System.out::print);
I got an error--- The operator > is undefined for the argument type(s) Stream<Integer>, int
but when I use the flatMap in the map no error why
Stream<List<Integer>> s1=Stream.of(a1);
s1.flatMap(x->x.stream()).filter(x->x>2).forEach(System.out::print);
If you are calling map(x->x.stream()) on a Stream<List<Integer>>, you'll get a Stream<Stream<Integer>>. You cannot apply .filter(x->x>2) on the elements of that Stream, since those elements are Stream<Integer>s, and the > operator requires two numeric operands.
If you use flatMap instead of map, you are converting your Stream<List<Integer>> to a Stream<Integer> whose elements are all the elements of all the Lists of the original Stream. Therefore, you can apply the .filter(x->x>2) filter on them.
Stream<List<Integer>> s1 = Stream.of(a1);
s1.map(x -> x.stream()).filter(x -> x > 2).forEach(System.out::print);
This will give error as you are not using flat map so filtering not possible whole (Streams >2). You can try like this:
Stream<List<Integer>> s1 = Stream.of(a1);
s1.map(x -> x.stream()).filter(x -> x.findFirst().get() > 2).forEach(System.out::print);
As we cannot apply.filter(x->x>2) on we will requires two numeric operands. s1.map(x -> x.stream()).filter(x -> x.findFirst().get() > 2).forEach(System.out::print); if we will take this then filter will find find matching element value which is greater than 2. In short we have to use flatmap to find greater than 2 in those streams or any operation to fetch numeric operands from stream then only it work.

Find Max of Multiple Lists

I'm pretty new to java streams and am trying to determine how to find the max from each list, in a list of lists, and end with a single list that contains the max from each sublist.
I can accomplish this by using a for loop and stream like so:
// databaseRecordsLists is a List<List<DatabaseRecord>>
List<DatabaseRecord> mostRecentRecords = new ArrayList<>();
for (List<DatabaseRecord> databaseRecords : databaseRecordsLists) {
mostRecentRecords.add(databaseRecords.stream()
.max(Comparator.comparing(DatabaseRecord::getTimestamp))
.orElseThrow(NoSuchElementException::new));
}
I've looked into the flatMap api, but then I'll only end up with a single map of all DatabaseRecord objects, where I need a max from each individual list.
Any ideas on a cleaner way to accomplish this?
You don't need flatMap. Create a Stream<List<DatabaseRecord>>, and map each List<DatabaseRecord> of the Stream to the max element. Then collect all the max elements into the output List.
List<DatabaseRecord> mostRecentRecords =
databaseRecordsLists.stream()
.map(list -> list.stream()
.max(Comparator.comparing(DatabaseRecord::getTimestamp))
.orElseThrow(NoSuchElementException::new))
.collect(Collectors.toList());
Based on the comments, I suggested to rather ignore the empty collection, otherwise, no result would be returned and NoSuchElementException thrown even the empty collection might (?) be a valid state. If so, you can improve the current solution:
databaseRecordsLists.stream()
.filter(list -> !list.isEmpty()) // Only non-empty ones
.map(list -> list.stream()
.max(Comparator.comparing(DatabaseRecord::getTimestamp)) // Get these with max
.orElseThrow(NoSuchElementException::new)) // Never happens
.collect(Collectors.toList()); // To List
If you use a version higher than Java 8:
As of Java 10, orElseThrow(NoSuchElementException::new) can be subsituted with orElseThrow().
As of Java 11, you can use Predicate.not(..), therefore the filter part would look like: .filter(Predicate.not(List::isEmpty)).

How to convert List<Optional<Type>> into List<Type>

I have extracted values from a Map into a List but got a List<Optional<TXN_PMTxnHistory_rb>>, and I want to convert it into List<TXN_PMTxnHistory_rb>.
My code:
List<Optional<TXN_PMTxnHistory_rb>> listHistory_rb6 =
listHistory_rb5.values()
.stream()
.collect(Collectors.toList());
I'd like to obtain a List<TXN_PMTxnHistory_rb>.
Filter out all the empty values and use map to obtain the non-empty values:
List<TXN_PMTxnHistory_rb> listHistory_rb6 =
listHistory_rb5.values()
.stream()
.filter(Optional::isPresent)
.map(Optional::get)
.collect(Collectors.toList());
It's possible to do this using a method called flatMap on the stream of Optionals which will remove any 'empty' Optionals.
List<TXN_PMTxnHistory_rb> listHistory_rb6 =
listHistory_rb5.values()
.stream()
.flatMap(Optional::stream)
.collect(Collectors.toList());
Flatmap is essentially performing two things - "mapping" and "flattening". In the mapping phase it calls whatever method you've passed in and expects back a new stream - in this case each Optional in your original List will become a Stream containing either 1 or 0 values.
The flatten phase will then create a new Stream containing the results of all the mapped Streams. Thus, if you had 2 Optional items in your List, one empty and one full, the resulting Stream would contain 0 elements from the first mapped Stream, and 1 value from the second.
Another option is to get all values and then filter out nulls:
List<TXN_PMTxnHistory_rb> listHistory_rb6 =
listHistory_rb5.values().stream()
.map(opt -> opt.orElse(null))
.filter(Objects::nonNull)
.collect(Collectors.toList());

does this Stream object create an infinite list of chimp objects or just one chimp object?

In the OCP studybook there is a line of code I don't entirely understand. It goes like this:
Stream<String> infinite = Stream.generate(() -> "chimp");
Does this create an infinite stream with just one element called chimp or does it infinitly generate chimp strings. Thank you.
Stream java.util.stream.Stream.generate(Supplier s)
Returns an infinite sequential unordered stream where each element is generated by the provided Supplier. This is suitable for generating constant streams, streams of random elements, etc.
It will create an infinite Stream, which means a Stream with infinite number of elements. All the elements will be the same String instance, since "chimp" will always return the same String instance from the String pool.
If you change it to
Stream<String> infinite = Stream.generate(() -> new String("chimp"));
each String element of this Stream will be a unique instance.
Nothing will happen unless there is a terminal operation in the stream pipeline please see Stream operations and pipelines section. For example this code:
infinite.forEach(System.out::println); // chimp ....
will print infinitive number of chimp Strings.
However this line will print only one String
infinite.limit(1).forEach(System.out::println); // chimp
On the other side
Stream.generate(() -> "chimp");
Has no effect, there no terminal operation in the stream's pipeline.
Intermediate operations return a new stream. They are always lazy;
executing an intermediate operation such as filter() does not actually
perform any filtering, but instead creates a new stream that, when
traversed, contains the elements of the initial stream that match the
given predicate. Traversal of the pipeline source does not begin until
the terminal operation of the pipeline is executed.

Categories

Resources