How to convert List<List<Double>> to List<Double[]> and to List<double[]> with Java 8 stream API? - java-8

I got stuck with this problem.
I've found similar answers here, but none of those solves the problem.
Should I use mapToDouble() here? Is there anything like "mapToDoubleArray"?

To convert a List<List<Double>> into a List<double[]>, you need to map each inner list into a double array using mapToDouble combined with toArray() (which is the "mapToDoubleArray" operation you are looking for).
List<double[]> res =
myList.stream()
.map(l -> l.stream().mapToDouble(d -> d).toArray())
.collect(toList());
If you want a List<Double[]> instead, you can simply use .map(list -> list.toArray(new Double[list.size()])).

Related

How do I use multiple reactive streams in the same pipeline?

I'm using WebFlux to pull data from two different REST endpoints, and trying to correlate some data from one stream with the other. I have Flux instances called events and egvs and for each event, I want to find the EGV with the nearest timestamp.
final Flux<Tuple2<Double,Object>> data = events
.map(e -> Tuples.of(e.getValue(),
egvs.map(egv -> Tuples.of(egv.getValue(),
Math.abs(Duration.between(e.getDisplayTime(),
egv.getDisplayTime()).toSeconds())))
.sort(Comparator.comparingLong(Tuple2::getT2))
.take(1)
.map(v -> v.getT1())));
When I send data to my Thymeleaf template, the first element of the tuple renders as a number, as I'd expect, but the second element renders as a FluxMapFuseable. It appears that the egvs.map(...) portion of the pipeline isn't executing. How do I get that part of the pipeline to execute?
UPDATE
Thanks, #Toerktumlare - your answer helped me figure out that my approach was wrong. On each iteration through the map operation, the event needs the context of the entire set of EGVs to find the one it matches with. So the working code looks like this:
final Flux<Tuple2<Double, Double>> data =
Flux.zip(events, egvs.collectList().repeat())
.map(t -> Tuples.of(
// Grab the event
t.getT1().getValue(),
// Find the EGV (from the full set of EGVs) with the closest timestamp
t.getT2().stream()
.map(egv -> Tuples.of(
egv.getValue(),
Math.abs(Duration.between(
t.getT1().getDisplayTime(),
egv.getDisplayTime()).toSeconds())))
// Sort the stream of (value, time difference) tuples and
// take the smallest time difference.
.sorted(Comparator.comparingLong(Tuple2::getT2))
.map(Tuple2::getT1)
.findFirst()
.orElse(0.)));
what i think you are doing is that you are breaking the reactive chain.
During the assembly phase reactor will call each operator backwards until it finds a producer that can start producing items and i think you are breaking that chain here:
egvs.map(egv -> Tuples.of( ..., ... )
you see egvs returns something that you need to take care of and chain on to the return of events.map
I'll give you an example:
// This works because we always return from flatMap
// we keep the chain intact
Mono.just("foobar").flatMap(f -> {
return Mono.just(f)
}.subscribe(s -> {
System.out.println(s)
});
on the other hand, this behaves differently:
Mono.just("foobar").flatMap(f -> {
Mono.just("foo").doOnSuccess(s -> { System.out.println("this will never print"); });
return Mono.just(f);
});
Because in this example you can see that we ignore to take care of the return from the inner Mono thus breaking the chain.
You havn't really disclosed what evg actually is so i wont be able to give you a full answer but you should most likely do something like this:
final Flux<Tuple2<Double,Object>> data = events
// chain on egv here instead
// and then return your full tuple object instead
.map(e -> egvs.map(egv -> Tuples.of(e.getValue(), Tuples.of(egv.getValue(), Math.abs(Duration.between(e.getDisplayTime(), egv.getDisplayTime()).toSeconds())))
.sort(Comparator.comparingLong(Tuple2::getT2))
.take(1)
.map(v -> v.getT1())));
I don't have compiler to check against atm. but i believe that is your problem at least. its a bit tricky to read your code.

Spring Reactor Set of Sets Combine to a Set

I'm trying to figure out how to get a Mono<Set<Customer>> from Flux<Order> .
Given that Order contains Set<Customer>
I've been trying to read all over and here is the closest i can get but it still wont compile. Can someone offer a hand please. In following example, orderService.getAll(orderCriteria) returns Flux<Order>
final Mono<Set<Customer>> customerSetMono = orderService
.getAll(orderCriteria)
.map(order -> order.getCustomers())
.collect(Collectors.toSet()) //Mono<Set<Set<Customer>>
.flatMap(
customerSet -> customerSet.stream()
.flatMap(customers -> customers.stream()))
.collect(Collectors.toSet());
You're facing a list inside a list scenario but in a reactive context. So, all you need to do is use a proper variant of flatMap. Here's how your code should look like
orderService.getAll(orderCriteria) // Flux<Order>
.flatMapIterable(Order::getCustomers) // Flux<Customer>
.collect(Collectors.toSet()); // Mono<Set<Customer>>

List of lists and Java 8

I have a list of class R with list of other class P
List<R> rList = getRListFromDb();
I would like to get the all the P objects in another list
List<P> result = new ArrayList<>();
I tried these, but giving me Class cast exception, saying class P cannot be converted to class R. By the way I have seen issue given below, but tried and could not figure it out.
How can I turn a List of Lists into a List in Java 8?
1. rList.stream().map(R::getP).flatMap(List::stream).forEach(result::addAll);
2. rList.forEach(r -> result.addAll(r.getP()));
I would like to what is incorrect here and also would like to know different ways of getting this done in Java 8.
rList.stream().map(R::getP).flatMap(List::stream).forEach(result::addAll);
would work if you didn't use flatMap (since addAll requires a Collection, but flatMap transforms your Stream<List<P>> to a Stream<P>.
This would work:
rList.stream().map(R::getP).forEach(result::addAll);
With flatMap it should be:
rList.stream().map(R::getP).flatMap(List::stream).forEach(result::add);
That said, the correct way is to use collect:
List<P> result = rList.stream()
.map(R::getP)
.flatMap(List::stream)
.collect(Collectors.toList());
or
List<P> result = rList.stream()
.flatMap(r -> r.getP().stream())
.collect(Collectors.toList());

java8 stream collect different list

I want to convert the input list to different list after filter. Please let know how to implement in java8 stream.
I tried something like below, it gave compilation error "p cannot be resolved to a variable" in getOutput() in collect().
List<Output> outputList= inputList.stream()
.filter(p -> p.param1==10)
.collect(Collectors.toList(getOutput(p)));
private Output getOutput(Input inp){
Output out = new Output();
out.value1= inp.value1;
---
---
}
As suggested by the comments you can do something like this
List<Output> outputList= inputList.stream()
.filter(p -> p.param1==10)
.map(j -> getOutput(j))
.collect(Collectors.toList());
So after the filter you convert the objects to your other type and finally collect. Alternatively, you can use the mapping collector to transform your objects into another kind and then collect them like below
List<Output> outputList= inputList.stream()
.filter(p -> p.param1==10)
.collect(Collectors.mapping(j -> getOutput(j), Collectors.toList()));

LINQ from SortedList C#

I'm fairly new to C#, and completely new to LINQ.
I have an existing object of type SortedList, which I would like to filter through using LINQ. However I appear to be having issues with this, apparently as the SortedList type is not generic.
For the timebeing I've looped through the entire SortedList and manually added the objects within to a List and used LINQ to filter from there. However, that seems to me, well, rubbish.
Is there a better way to convert my SortedList to List<> (I'm not bothered about preserving the key)? Or indeed to convert my SortedList to SortedList<> perhaps?
Original SortedList class is part of Collection. Generics introduces SortedList but if you have old code, then it wont be using that.
The easiest is to use the Cast method or OfType extension method that is made available for SortedList. Those methods will give you IEnumerable list that you can apply generic Linq operations. Make sure you include using System.Linq; in the beginning then you should be able to do like below:
sortedList.Cast<int>().Where(i=>i > 5);
sortedList.OfType<Car>().Where(c=> c.Color == Color.Blue);
If you don't need to filter by Keys, just cast and filter on Values
SortedList sl = new SortedList();
sl.Add("foo", "baa");
var baas = sl.Values.Cast<string>().Where(s => s == "baa");
What about
normalList = sortedList.Items;
Does that give you the list you want?
To answer the question "Is there a better way to convert my SortedList to List<> (I'm not bothered about preserving the key)?"... Here is example, with last line as the answer, resulting in list with integers 4, 1, 3, 2:
SortedList<string,int> sortedList = new SortedList<string,int>();
sortedList.Add("One", 1);
sortedList.Add("Two", 2);
sortedList.Add("Three", 3);
sortedList.Add("Four", 4);
List<int> list = sortedList.Values.ToList();

Resources