Пытаюсь решить задачу на Java именно с помощью лямбда выражения.
Необходимо в одном лямбда выражении обойти числа от 1 до 1000 и получить массив чисел(выборку из чисел от 1 до 1000), суммы квадратов цифр которых это четные числа.
Это вариант без лямбда:
List<Integer> list = new ArrayList<>();
for (int i = 1; i<1001; i++){
int sum = 0;
for(int a=i; a>0; a/=10){
sum += (a%10)*(a%10);
}
if (sum%2==0) list.add(i);
}
Если кто представляет как, пожалуйста, помогите.
Код поправил, спасибо.
В первом приближении задача решается так:
List<Integer> result = IntStream.range(1, 1000)
.filter(n -> isDigitsSquaresEven(n))
.boxed()
.collect(Collectors.toList())
IntStream.range()
даёт нам стрим из int
'ов от 1 до 1000 (не включая 1000) с шагом 1. Это практически аналог самого простого цикла for
. Дальше при помощи условия в filter
мы проверяем, какие из элементов стрима подходят под наше условие (сумма квадратов цифр должна быть чётной) и оставляем только их. Затем собираем все оставшиеся числа в список. Обратите внимание на boxed()
- с его помощью мы переходим от IntStream
к обычному Stream
, чтобы была возможнось использовать более простую перегрузку collect()
.
Само собой, мы можем isDigitsSquaresEven()
реализовать как отдельный метод, в котором будут все проверки, но это же не интересно! Давайте превратим его в лямбду. Тут нам поможет IntStream.iterate()
. С его помощью можно получить стрим, который начинается с определённого числа, а каждое последующее число будет результатом применения функции к предыдущему. Например,
int num = 192837;
IntStream ints = IntStream.iterate(num, i -> i / 10);
даст нам стрим, состоящий из результатов деления исходного числа 192837 на 10: 192837, 19283, 1928, 192, 19, 1, 0, 0, 0... Стрим бесконечный, поэтому его нужно как-то ограничить. filter
нам тут не поможет: он хоть и отбросит все нули, но IntStream.iterate()
продолжит производить числа до бесконечности. Ограничивать нужно именно количество производимых чисел, и тут нам поможет limit()
. Как узнать, сколько чисел брать? Очень просто - значение десятичного логарифма исходного числа даст нам количество разрядов в нём: Math.log10(192837) == 5.2851903664659154
. Округляем и получаем нужное число: Math.floor(Math.log10(192837)) + 1 == 6.0
. Округляем вниз из-за свойств десятичного логарифма: log10(1) == 0
, log10(10) == 1
, log10(100) == 2
. Теперь можно и логику добавить:
int num = 192837;
int sum = IntStream.iterate(num, i -> i / 10)
// Сейчас стрим бесконечный: 192837, 19283, 1928, 192, 19, 1, 0, 0, 0...
.limit(((Double) Math.floor(Math.log10(num))).longValue() + 1)
// А сейчас в нём всего 6 элементов: 192837, 19283, 1928, 192, 19, 1
.map(i -> i % 10)
// Теперь в стриме цифры исходного числа: 7, 3, 8, 2, 9, 1
.map(i -> i * i)
// Теперь - их квадраты: 49, 9, 64, 4, 81, 1
.sum()
// Теперь - их сумма: 208
Начиная с Java 9 в стримах есть метод takeWhile()
, с помощью которого можно ограничить стрим условием:
int sum = IntStream.iterate(num, i -> i / 10)
.takeWhile(i -> i > 0)
.map(i -> i % 10)
.map(i -> i * i)
.sum()
Собираем всё вместе и получаем:
List<Integer> result = IntStream.range(1, 1000)
.filter(num ->
IntStream.iterate(num, i -> i / 10)
.limit(((Double) Math.floor(Math.log10(num))).longValue() + 1)
.map(i -> i % 10)
.map(i -> i * i)
.sum() % 2 == 0
)
.boxed()
.collect(Collectors.toList())
Или, в Java 9 варианте:
List<Integer> result = IntStream.range(1, 1000)
.filter(num ->
IntStream.iterate(num, i -> i / 10)
.takeWhile(i -> i > 0)
.map(i -> i % 10)
.map(i -> i * i)
.sum() % 2 == 0
)
.boxed()
.collect(Collectors.toList())
Я старался по максимому написать все с использованием лямбды, но не так все просто оказалось...
import java.util.ArrayList;
import java.util.List;
import java.util.stream.IntStream;
public class Lyambda {
public static void main(String[] args) {
List<Integer> list = new ArrayList<>();
IntStream.range(0, 1000).forEach(
i -> {
int sum = 0;
int number = i;
for(int j = 0; j < ("" + i).length(); j++) {
sum += (int) Math.pow(number%10, 2);
number = number/10;
}
if (sum%2 == 0)
// System.out.println("i = " + i + " sum = " + sum);
list.add(i);
}
);
//Проверка
for (Integer integer : list) {
System.out.println(integer);
}
}
}
Откуда я брал информацию:
http://www.adam-bien.com/roller/abien/entry/java_8_from_ordinary_for
https://stackoverflow.com/questions/1306727/way-to-get-number-of-digits-in-an-int
Могу предложить такое извращение (про порядок в выборке вроде не упоминалось)
public class RecExample {
List<Integer> list = new ArrayList<>();
Consumer<Integer> recConsumer = i -> {
if (i < 2)
return;
if ((String.valueOf(i).chars().map(c -> c - 48).reduce(0, (a, c) -> a + c * c) & 1) == 0)
list.add(i);
this.recConsumer.accept(i - 1);
};
public static void main(String[] args) {
RecExample recExample = new RecExample();
recExample.recConsumer.accept(1000);
System.out.println(recExample.list);
}
}
Айфон мало держит заряд, разбираемся с проблемой вместе с AppLab
Перевод документов на английский язык: Важность и ключевые аспекты
Я купил вдс сервер и установил на нем Tomcatна вдс есть ip и домен (которые вроде привязан к этому ip) Кинул свой проект в webapps