How to convert Long to BigDecimal while also using a Stream - java

I'm struggling to understand how can I make the following code work.
The field count_human_dna of my stat class is of type BigDecimal, with setting the type as Long this works, but I need to change it to BigDecimal, can somehow tell me how could I make this work for BigDecimal field?
stat.setCount_human_dna(dnaSamples.stream()
.filter(x -> x.getType().equals("Human"))
.collect(Collectors.counting()));
This code is counting all the dnaSamples which type belong to Human.

Use the BigDecimal#valueOf method for the conversion from long to BigDecimal.
stat.setCount_human_dna(BigDecimal.valueOf(dnaSamples.stream().filter(x -> x.getType().equals("Human")).collect(Collectors.counting())));
See the JavaDocs for more detail.

The most simple and efficient way to do is to use terminal operation count() which returns the number of elements in the stream as long and then convert into BigDecimal:
stat.setCount_human_dna(getDNACount(dnaSamples));
public static BigDecimal getDNACount(Collection<Sample> dnaSamples) {
long humanSamples = dnaSamples.stream()
.filter(x -> x.getType().equals("Human"))
.count();
return BigDecimal.valueOf(humanSamples);
}
And you can produce the result of type BigDecimal directly from the stream using reduce() a terminal operation:
stat.setCount_human_dna(getDNACount(dnaSamples));
public static BigDecimal getDNACount(Collection<Sample> dnaSamples) {
return dnaSamples.stream()
.filter(x -> x.getType().equals("Human"))
.reduce(BigDecimal.ZERO,
(total, next) -> total.add(BigDecimal.ONE),
BigDecimal::add);
}
Sidenote: I'm not an expert in such questions as DNA analysis, but the result of this reduction will always be a whole number. You might consider utilizing BigInteger instead of BigDecimal.

Related

given an infinite sequence break it into intervals, and return a new infinite sequence with the average of each interval

i have to calculate the average of a Infinite Sequence using Stream API
Input:
Stream<Double> s = a,b,c,d ...
int interval = 3
Expected Result:
Stream<Double> result = avg(a,b,c), avg(d,e,f), ....
the result can be also an Iterator, or any other type
as long as it mantains the structure of an infinite list
of course what i written is pseudo code and doesnt run
There is a #Beta API termed mapWithIndex within Guava that could help here with certain assumption:
static Stream<Double> stepAverage(Stream<Double> stream, int step) {
return Streams.mapWithIndex(stream, (from, index) -> Map.entry(index, from))
.collect(Collectors.groupingBy(e -> (e.getKey() / step), TreeMap::new,
Collectors.averagingDouble(Map.Entry::getValue)))
.values().stream();
}
The assumption that it brings in is detailed in the documentation clearly(emphasized by me):
The resulting stream is efficiently splittable if and only if stream
was efficiently splittable and its underlying spliterator reported
Spliterator.SUBSIZED. This is generally the case if the underlying
stream comes from a data structure supporting efficient indexed random
access, typically an array or list.
This should work fine using vanilla Java
I'm using Stream#mapMulti and a Set external to the Stream to aggregate the doubles
As you see, I also used DoubleSummaryStatistics to count the average.
I could have use the traditional looping and summing then dividing but I found this way more explicit
Update:
I changed the Collection used from Set to List as a Set could cause unexpected behaviour
int step = 3;
List<Double> list = new ArrayList<>();
Stream<Double> averagesStream =
infiniteStream.mapMulti(((Double aDouble, Consumer<Double> doubleConsumer) -> {
list.add(aDouble);
if (list.size() == step) {
DoubleSummaryStatistics doubleSummaryStatistics = new DoubleSummaryStatistics();
list.forEach(doubleSummaryStatistics::accept);
list.clear();
doubleConsumer.accept(doubleSummaryStatistics.getAverage());
}
}));

How to find max length in list of string using streams in Java?

I have a class like below:
public class A
{
String name;
String getName(){return name;}
}
And I also have a list like below:
List<A> list_a = new ArrayList<>();
//add n objects into list_a
Right now I would like to find the max length of object which is in list_a using streams in Java. I have created code like below:
final int max_len = list_a.stream().max(Comparator.comparingInt(A::getName::length));
But it does not work, I mean it is something bad with syntax. Could you help me with this? Thank you.
What you are using isn't lambda. Lambda looks like (arguments) -> action. What you have in A::getName is method reference, but additional ::length is not part of its syntax.
Instead of A::getName::length you can use lambda like a -> a.getName().length().
But your code has yet another problem. Code
list_a.stream()
.max(Comparator.comparingInt(A::getName::length));
is handling streams of A and max method called on Stream<A> will result in Optional<A> not int. It is Optional because there is a chance that list_a can be empty which means that there will be no valid result.
If you want to get OptionalInt you would need to map Stream<A> to Stream<String> and then map it to Stream of ints first. Then you can call its max() method and get:
OptionalInt maxOpt = list_a.stream()
.map(A::getName)
.mapToInt(String::length)
.max();
When you already have OptionalInt you can use it to check if value there isPresent() and get it via getAsInt(). You can also use orElse(defaultValueIfEmpty) like
int max = maxOpt.orElse(-1); //will return value held by maxOpt, or -1 if there is no value
You can use an IntStream as you're just looking for the max length:
OptionalInt oi = list_a.stream()
.map(A::getName)
.mapToInt(String::length)
.max()
final int max_len = oi.orElse(0); //defaulting to 0
If you need to use a custom comparator, you will need a lambda expression:
final int max_len = list_a.stream()
.max(Comparator.comparingInt(a ->
a.getName().length())) //need a lambda
.map(A::getName)
.map(String::length)
.orElse(0); //defaulting to 0
Alternative solution using Collections.max:
A a = Collections.max(list_a, Comparator.comparing(obj -> obj.getName().length()));
int maxLen = a.getName().length();
Keep in mind that Collections.max throws NoSuchElementException if the collection is empty. If you don't want it, use the approach with OptionalInt like in #Pshemo's answer.

Get min and max of supplier streams

I know if i use:
double data[][] = new double[n][];
// fill the array
DoubleStream stream = Arrays.stream(data).flatMapToDouble(Arrays::stream);
int max = stream.max().getAsDouble();
DoubleStream stream = Arrays.stream(data).flatMapToDouble(Arrays::stream);
int min = stream.min().getAsDouble();
i will get the minimum and maximum of whatever value the stream has as a double.
However i cant for the life of me figure out how to make it into a "Supplier". since
Supplier<Stream> stream = (Supplier<Stream>) Arrays.stream(data).flatMapToDouble(Arrays::stream);
double max = stream.max().getAsDouble();
double min = stream.min().getAsDouble();
doesn not work, and Supplier<DoubleStream> does not work ether.
i managed to get it to work with
Supplier<DoubleStream> stream = () -> Arrays.stream(t).flatMapToDouble(Arrays::stream);
OptionalDouble max = stream.get().max();
OptionalDouble min = stream.get().min();
but why did the values in the stream become a OptionalDouble?
Casting a DoubleStream to a Supplier<DoubleStream> does not make a DoubleStream a Supplier<DoubleStream>.
You need a lambda expression () -> stream to form a supplier of the stream:
Supplier<DoubleStream> supplier = () -> Arrays.stream(data).flatMapToDouble(Arrays::stream);
The max value then can be determined by:
double max = supplier.get().max().orElse(Double.MIN_VALUE);
// where Double.MIN_VALUE can be any other default 'double' value if max is not present
since the max() over DoubleStream returns an OptionalDouble.
The Supplier<T> functional interface has a single abstract method:
#FunctionalInterface
public Supplier<T> {
T get();
}
As it's a functional interface, you could use a lambda expression (or a method reference) to create an instance of the Supplier type:
Supplier<Integer> supplier = () -> 1;
If you change the Integer generic type to DoubleStream, then you'd get what you want:
Supplier<DoubleStream> supplier = Arrays.stream(data).flatMapToDouble(Arrays::stream);
Casting is not magic: if you have a DoubleStream instance, you can't just cast that instance to Supplier<DoubleStream> and expect the cast to magically transform the stream to a supplier.
Despite all this, it's not clear at all why you need to get a supplier from the stream in the first place.
Regarding the return type of DoubleStream.max and DoubleStream.min methods, it's OptionalDouble (instead of just double) because the stream might be empty, in which case there would be neither a max nor a min value. In this case, the returned OptionalDouble instance would be empty.

Sum Bigdecimals inside Stream

I´m using Java 8 Stream where I iterate over two collections, and after pass a filter I want to sum one of the bigdecimal variables that I have inside my stream to an external bigDecimal variable "restrictionsNumber"
Here my code:
final BigDecimal restrictionsNumber = cmd.amount.getNumberOfUnits();
order.products()
.stream()
.flatMap(product -> product.getRestrictions()
.stream()
.filter(restriction -> restriction.equals(newProductRestriction))
.map(restriction -> restrictionsNumber.add(product.getAmount()
.getNumberOfUnits())));
The last map is the one where I´m trying to sum the two bigdecimals.
I know I´m doing something wrong.
Can anyone give me an advise about how to do it with Stream.
I´m trying to refactor from this old fashion code
final BigDecimal restrictionsNumber = cmd.amount.getNumberOfUnits();
for (Product product : order.products()) {
for (String oldProductRestriction : product.getRestrictions()) {
if (oldProductRestriction.equals(newProductRestriction)) {
restrictionsNumber = restrictionsNumber.add(product.getAmount()
.getNumberOfUnits());
}
}
}
Regards.
This may be what you need (but it keeps adding the same amount several times for each product, in line with your original code, which seems weird):
BigDecimal sum = order.products()
.stream()
.flatMap(product -> product.getRestrictions()
.stream()
.filter(restriction -> restriction.equals(newProductRestriction))
.map(restriction -> product.getAmount().getNumberOfUnits()))
.reduce(BigDecimal.ZERO, BigDecimal::add);
BigDecimal result = restrictionsNumber.add(sum);
It sounds like you want to use the "reduce" operation.
Reduce is used for operations like summing over a whole stream, or adding finding the maximum.
(If you want your addition to happen for a single stream element then your question was unclear to me, please add detail)

Is there a way to typecast a whole list of Big Decimals to list of Long values

If I have a List of BigDecimal objects, is it possible to typecast the whole list to a List of Long values without having to iterate over every BigDecimal object?
You will need to iterate one way or another. If you want to "hide" the iteration, you can use a stream:
List<Long> longs = bigs.stream().map(BigDecimal::longValue).collect(Collectors.toList());
But there will still be an iteration in the background.
You mention that you don't want to iterate twice - you could save the stream of longs for later use:
LongStream longs = bigs.stream().mapToLong(BigDecimal::longValue);
And apply additional operations on that stream before collecting the results.
Without Java 8 streams, you can use guava transform:
private List<Long> convertToLongList(List<BigDecimal> bigDecimalList) {
return Lists.transform(bigDecimalList, new Function<BigDecimal, Long>() {
public Long apply(BigDecimal bigDecimal) {
return bigDecimal.longValue();
}
});
}

Categories

Resources