У меня есть HashSet<Double>, из которого я хочу извлечь те элементы, которые являются целыми числами, т.е. те элементы, у которых все нули после запятой. Есть ли стандартный способ сделать это? Я мог бы сделать что-то окольное, например: учитывая двойное x, я могу посмотреть на все значения после десятичной точки и увидеть, все ли они равны нулю, но это кажется запутанным.
Имейте в виду, что большие double числа не имеют достаточной точности, чтобы определить, было ли предназначено целое число.
Также следует определиться с допуском. 2.000_000_000_000_000_4, вероятно, было 2 с неточностью, поэтому вы, вероятно, захотите рассматривать его как целое число, в зависимости от ваших обстоятельств.




вы можете преобразовать их в целое число и приравнять приведенное значение к исходному
double d = 1.5;
if ((int)d==d) // integer
else // not integer
Работает только в диапазоне int. Я предполагаю, что 2_147_483_649.0 (также пишется 2.147483649E9) считается целым числом, но ваше условие if оценивается как ложное.
да. но вы можете сделать то же самое с BigDecimal и сравнить его с bigDecimal.toBigInteger()
Вы можете сделать что-то вроде этого:
HashSet<Double> hd = new HashSet<> ();
hd.add (3.5);
hd.add (2.0);
hd.add (3.444);
hd.add (-1.0);
Set<Double> filtered = hd.stream()
.filter (x -> (int)(double)x == x)
.collect (Collectors.toSet());
System.out.println (filtered);
Выход:
[2.0, -1.0]
Сначала вы должны привести Double к double, а затем к int. Если этот int равен исходному Double, этот Double имеет целочисленное значение.
Если вы хотите избежать явного приведения, вы можете изменить
.filter (x -> (int)(double)x == x)
к
.filter (x -> x.intValue() == x)
который делает то же самое.
"Кастинг" Double на double? Это звучит очень подозрительно для меня; конечно, это приведет к (автоматической) распаковке, но правильный способ сделать это — привести неупакованное двойное значение ((int)x.doubleValue()). И если мы уже говорим об этом: сравнение ``ìntwith a Double``` работает из-за автораспаковки, но чтобы сделать это действительно правильно, сделайте это: x.intValue() == x.doubleValue().
@tquadrat приведение Double к double требуется, так как вы не можете напрямую привести Double к int. Да, приведение Double к double эквивалентно x.doubleValue(). «Правильный путь» — это вопрос мнения. Я думаю, что x.intValue() == x выглядит лучше, и да, это работает благодаря автоматической распаковке.
– Да, нужно преобразовать Double в double, но это не «приведение», это «распаковка»… и обычно делается вызовом метода Double::doubleValue(), либо явно, либо неявно, как автораспаковка…
Я думаю, вам нравится иметь окончательный результат целых чисел, а не двойников. Например. 7, а не 7.0.
Итак, попробуйте этот:
Set<Double> set = new HashSet<>();
set.add(6.4);
set.add(10.44);
set.add(7.0);
Set<Integer> filtered = set.stream()
.filter(item -> Math.floor(item) == item)
.map(Double::intValue)
.collect(Collectors.toSet());
System.out.println(filtered);
Попробуй это:
Collection<Integer> filterIntegers( final HashSet<Double> doubles )
{
final var retValue = doubles.stream()
.filter( d -> d.doubleValue() == d.intValue() )
.map( Double::intValue )
.collect( Collector.toSet() );
return retValue;
}
Явное сравнение действительного (двойного) значения d с его целым значением кажется мне наиболее точной реализацией требования. Никаких переборов, никаких математических операций (хотя все это дает одинаковые результаты!).
Вам придется сделать что-то обходное, потому что для JVM любое двойное значение является двойным значением, и она не проверяет, достаточно ли близко такое значение к целому числу.