I have the following list of double values:
items {9.0, 4.0, 16.0, -6.0, 5.0}
I want to find the maximum and minimum values and for that I did:
double max = items.stream().max(Comparator.comparing(String::valueOf)).get();
double min = items.stream().min(Comparator.comparing(String::valueOf)).get();
The result that I got is max=9.0 and min=-6.0. I was expecting the maximum to be 16.0. Later, I changed 16.0 to 92.0 and it worked; it gave me max=92.0
Do you know how to solve that?
You don't want to compare using strings but by the natural order of your double elements, i.e. Comparator.naturalOrder() instead of Comparator.comparing(String::valueOf).
Comparing via strings will result in the characters being compared and since the character value of 9 (of "9.0") is greater than 1 (of "16.0") you get the result you see. Changing "16.0" to "92.0" will result in . to be compared with 2 (since the first character is equal) and thus "92xx" is greater than "9.xx".
What about :
double max = items.stream().mapToDouble(Double::doubleValue).max().getAsDouble();//16.0
double min = items.stream().mapToDouble(Double::doubleValue).min().getAsDouble();//-6.0
It appears you want to compare the number numerically instead of their String representation e.g. "16.0" < "9.0" as '1' < '9'
List<Double> items = Arrays.asList(9.0, 4.0, 16.0, -6.0, 5.0);
double max = items.stream().max(Comparator.naturalOrder()).get();
double min = items.stream().min(Comparator.naturalOrder()).get();
System.out.println(min + " " + max);
prints
-6.0 16.0
There's a more appropriate stream type for doubles. Using it, you can get min and max in one terminal operation (eliminating the need to supply a comparator in the process):
DoubleSummaryStatistics stats = items.stream().mapToDouble(d -> d)
.summaryStatistics();
//even better: DoubleStream.of(9.0, 4.0, 16.0, -6.0, 5.0).summaryStatistics()
And stats will have:
count=5, sum=28.000000, min=-6.000000, average=5.600000, max=16.000000
Your are comparing them as String so by alphabetical order : 1xx is before 9xx
You need to compare then as Double or Integer, so use Comparator.comparing(Double::valueOf) (or Integer::valueOf)
items
.stream()
.sorted()
.limit(1)
.collect(Colletors.toList();
Related
Is there any way to get an average here via one iteration? I can do it with regular "For loop" but want to use stream instead.
final Double ratingSum = ratingCount.stream().mapToDouble(RecommendRatingCount::getRatingSum).sum();
final Double countSum = ratingCount.stream().mapToDouble(RecommendRatingCount::getCount).sum();
return ratingSum /countSum;
Assuming Java 12 or higher is used a teeing collector
return
ratingCount.stream()
.collect(Collectors.teeing(
Collectors.summingDouble(RecommendRatingCount::getRatingSum),
Collectors.summingDouble(RecommendRatingCount::getCount),
(sum, count) -> sum / count));
Decompose each object into separate ratings, each value being rating/count, by first expanding out each object count times, then converting each to its discounted value, then summarise all such values:
double average = ratingCount.stream()
.flatMap(rrc -> generate(() -> rrc).limit(rrc.getCount()))
.mapToDouble(rcc -> rcc.getRatingSum() / rcc.getCount())
.summaryStatistics().getAverage();
Assuming your RatingCount is a natural number.
return ratingCount.stream()
.flatMapToDouble(a -> DoubleStream.concat(DoubleStream.of(a.getRatingSum()),
DoubleStream.generate(() -> 0).limit((long) a.getCount() - 1)))
.average().orElse(0);
Supose i have a List of Integers: ints = {0,10,20,30,40,50} and an input value input = 17
How do i get the closest integer of the list to the given input? For my example it would be 20.
Or to restate the question: how do i round the input to the closest value of the list?
I couldn't find a function in Java that does something like that
There is nothing in Java to do this exactly, as it's not something that's particularly useful in general.
One approach would be to notice that you are looking for the smallest deviation from input, that is to say, the value where abs(number - input) is closest to 0.
Using this knowledge, we can create a Comparator that compares numbers based on their distance from the input, and pick the smallest number based on this comparator:
List<Integer> ints = List.of(0, 10, 20, 30, 40, 50);
int input = 17;
Comparator<Integer> distanceFromInputComparator =
Comparator.comparing(value -> Math.abs(value - input));
System.out.println(ints.stream().min(distanceFromInputComparator).orElseThrow());
This returns 20, as requested.
There are some caveats with this implementation that could be addressed if necessary. It currently throws an exception if the input list is empty. It also picks arbitrarily if there are two closest (e.g. if 14 & 20 are in the list and the input is 17, it's not specified which would be picked by Stream.min()) since they're both "equal" according to the comparator.
To address the tiebreaker, you could add a secondary comparison if they're equidistant. For instance, you could do either of the following:
// Pick the smaller when there's a tie
Comparator<Integer> distanceFromInputComparator = Comparator
.comparing((Integer value) -> Math.abs(value - input))
.thenComparing(Comparator.naturalOrder());
// Pick the larger when there's a tie
Comparator<Integer> distanceFromInputComparator = Comparator
.comparing((Integer value) -> Math.abs(value - input))
.thenComparing(Comparator.reverseOrder());
An algorithm:
Iterate through the list.
For each element, compare the element with the input value.
If the input value is greater than the current element, iterate to the next element.
If the input value is greater than all elements, return some sentry value (MAX_VALUE) or something.
If the input value is lesser than a given element, then it's rounded sufficiently and you would return that element.
There are ways to account for rounding down; you'll just have to reverse the direction of the inequality. Half-rounding is left as an exercise for the reader.
massTotal is printing out as a number ending in ".0" no matter what the decimal should be. The massCounter[] indexes are doubles. How do I make it round to the first decimal place, instead of to the whole number?
public static double massTotal(double[] massCounter) {
double massTotal = 0.0;
for (int i = 0; i < massCounter.length; i++) {
massTotal += Math.round(massCounter[i] * 10.0 / 10.0);
}
return massTotal;
}
Thanks!
Your Math.round function is basically rounding everything, i.e.
1.5 -> 2
22.4 -> 22
So therefore when they all get totalled in the method, it will always be x.0, which is just printing a whole number as a double, showing the first .0.
What you could do, is to completely remove the Math.round and then print the result with using String.format and it will show you the output with one decimal place.
String.format("%.1f", massTotal(myArray))
Or even easier, if you are allowed to use Java8 capabalities:
double total = DoubleStream.of(myArray).sum();
System.out.println(String.format("%.1f", total));
Online example
I have a String[][] array that looks like this.
All fields are stored as strings, doubles are concatenated into the array using "" +
01234567 Katie Brown 100.0 97.0 100.0 99.0 99.3
20051005 Jack Chan 100.0 97.0 100.0 99.0 99.3
02345678 John Smith 89.5 88.5 99.0 100.0 97.4
Assume that the double values range from 0.0 - 100.0
I wished to sort the array in descending order using the value of the last field (rightmost), so I used a custom comparator as such, which sorted the array in descending lexicographic value
// Sort the 2D array using the last column
Arrays.sort(array, new Comparator<String[]>() {
#Override
public int compare(String[] s1, String[] s2) {
String t1 = s1[numberOfData - 1];
String t2 = s2[numberOfData - 1];
return t2.compareTo(t1); // Descending order
}
});
This worked fine until I faced a situation where the last field was 100.0, like below
01234567 Katie Brown 100.0 97.0 100.0 99.0 100.0
It ends up coming dead last, since 100.0 is lexicographically lower than any other double value. (I think?)
Disregarding overhead and memory efficiency, is it possible to sort it by using the Double.parseDouble() value of the last field? How would I do so? Or is there a better way?
How could I always round up a double to an int, and never round it down.
I know of Math.round(double), but I want it to always round up.
So if it was 3.2, it gets rounded to 4.
You can use Math.ceil() method.
See JavaDoc link: https://docs.oracle.com/javase/10/docs/api/java/lang/Math.html#ceil(double)
From the docs:
ceil
public static double ceil(double a)
Returns the smallest (closest to negative infinity) double value that is greater than or equal to the argument and is equal to a mathematical integer. Special cases:
If the argument value is already equal to a mathematical integer, then the result is the same as the argument.
If the argument is NaN or an infinity or positive zero or negative zero, then the result is the same as the argument.
If the argument value is less than zero but greater than -1.0, then the result is negative zero.
Note that the value of Math.ceil(x) is exactly the value of -Math.floor(-x).
Parameters:
a - a value.
Returns:
The smallest (closest to negative infinity) floating-point value that is greater than or equal to the argument and is equal to a mathematical integer.
In simple words,
Math.ceil will always round UP or as said above, in excess.
Math.round will round up or down depending on the decimals.
If the decimal is equal or higher than 5, then it's rounded up.
decimal => 5. (1,5 = 2)
If the decimal is less than 5, then it's rounded down.
decimal < 5. (1,45 = 1)
Examples of Math.ceil and Math.round:
The code Below would return:
Cost, without Ceil 2.2 and with Ceil 3 (int), 3.0 (double). If we round it: 2
int m2 = 2200;
double rate = 1000.0;
int costceil = (int)Math.ceil(m2/rate);
double costdouble = m2/rate;
double costdoubleceil = Math.ceil(m2/rate);
int costrounded = (int)Math.round(m2/rate);
System.out.println("Cost, without Ceil "+costdouble+" and with Ceil "+
costceil+"(int), "+costdoubleceil+"(double). If we round it: "+costrounded);
If we change the value of m2 to for example 2499, the result would be:
Cost, without Ceil 2.499 and with Ceil 3 (int), 3.0 (double). If we round it: 2
If we change the value of m2 to for example 2550, the result would be:
Cost, without Ceil 2.55 and with Ceil 3 (int), 3.0 (double). If we round it: 3
Hope it helps. (Information extracted from previous answers, i just wanted to make it clearer).
tl;dr
BigDecimal( "3.2" ).setScale( 0 , RoundingMode.CEILING )
4
BigDecimal
If you want accuracy rather than performance, avoid floating point technology. That means avoiding float, Float, double, Double. For accuracy, use BigDecimal class.
On a BigDecimal, set the scale, the number of digits to the right of the decimal place. If you want no decimal fraction, set scale to zero. And specify a rounding mode. To always round an fraction upwards, use RoundingMode.CEILING, documented as:
Rounding mode to round towards positive infinity. If the result is positive, behaves as for RoundingMode.UP; if negative, behaves as for RoundingMode.DOWN. Note that this rounding mode never decreases the calculated value. So for example, 1.1 becomes 2, and your 3.2 becomes 4.
BigDecimal bd = new BigDecimal( "3.2" ) ;
BigDecimal bdRounded = bd.setScale( 0 , RoundingMode.CEILING ) ;
String output = bdRounded.toString() ;
System.out.println( "bdRounded.toString(): " + bdRounded ) ; // 4
4
See this code run live at IdeOne.com.
private int roundUP(double d){
double dAbs = Math.abs(d);
int i = (int) dAbs;
double result = dAbs - (double) i;
if(result==0.0){
return (int) d;
}else{
return (int) d<0 ? -(i+1) : i+1;
}
}
Good job ! ;)
My method is relatively simple, hope it works for you.
In my case I have a row of objects that can only hold 3 items and I must adjust the number of rows I have to accommodate the items.
So I have some Double numberOfRows, I then use numberOfRows.intValue() to get an int value for numberOfRows.
if the int value I get is less than numberOfRows, I add 1 to numberOfRows to round it up, else the value I get from numberOfRows.intValue() is the answer I want.
I wrote this simple for loop to test it out:
for(int numberOfItems = 0; numberOfItems < 16; numberOfItems++) {
Double numberOfRows = numberOfItems / 3.0;
System.out.println("Number of rows are: " + numberOfRows);
System.out.println("Number of items are: " + numberOfItems);
if(numberOfRows.intValue() < numberOfRows) {
System.out.println("int number of rows are: " + (numberOfRows.intValue() + 1));
}
else {
System.out.println("int value of rows are: " + numberOfRows.intValue());
}
System.out.println();
System.out.println();
}
Short example without using Math.ceil().
public double roundUp(double d){
return d > (int)d ? (int)d + 1 : d;
}
Exaplanation:
Compare operand to rounded down operand using typecast, if greater return rounded down argument + 1 (means round up) else unchanged operand.
Example in Pseudocode
double x = 3.01
int roundDown = (int)x // roundDown = 3
if(x > roundDown) // 3.01 > 3
return roundDown + 1 // return 3.0 + 1.0 = 4.0
else
return x // x equals roundDown
Anyway you should use Math.ceil(). This is only meant to be a simple example of how you could do it by yourself.
Math.ceil did not work for me. It keeps rounding down when I cast back to long. Below is my hack:
long pages = (userCnt % size) == 0 ? (userCnt / size) : (userCnt / size) + 1;
Simply check if Even or Odd and if Odd, add 1 to the result.
Math.ceil() will give you the closest lowest value if you want it to be rounded to largest closest values you should use Math.floor()