Java 8, поток с другим индексом списка на основе - PullRequest
4 голосов
/ 07 мая 2019

У меня есть этот код

List<Integer> numbers = new ArrayList<>(30, 25, 17, 12 ,8, 5, 3, 2));
List<Integer> indices = new ArrayList<>(5, 3, 2));
Integer newNumber = 1;
for (int i = indices.size() - 1; i >= 0; i--) {
  newNumber *= (numbers.get(indices.get(i)));
}

newNumber будет: 5*12*17 = 1020

Можно сделать с помощью Stream Reduce?

Позже мне нужноудалите индексы из исходных чисел (я думал в фильтре, но целью является индекс, а не объект Integer).

List<Integer> newNumbers = new ArrayList<>(numbers);
for (int i = indices.size() - 1; i >= 0; i--) {
  newNumbers.remove(indices.get(i).intValue()); // Remove position
}

В качестве альтернативы я думал в этом коде.

List<Integer> newNumbers2 = new ArrayList<>();
for (int i = 0; i < numbers.size(); i++) {
  if (!indices.contains(i)) {
    newNumbers2.add(numbers.get(i));
  }
}

Можно ли сделать это с помощью потока?

Спасибо.

Ответы [ 4 ]

2 голосов
/ 07 мая 2019

Да, вы можете сделать это с помощью простого сокращения. В этом случае единичный элемент сокращения равен 1.

int product = indices.stream().mapToInt(numbers::get).reduce(1, (n1, n2) -> n1 * n2);

Ответ на последний вопрос:

Set<Integer> indicesSet = new HashSet<>(indices);
List<Integer> newNumbers = IntStream.range(0, numbers.size())
    .filter(n -> !indicesSet.contains(n))
    .mapToObj(n -> numbers.get(n))
    .collect(Collectors.toList());

В математике элемент идентичности - это особый тип элемента установить в отношении двоичной операции на этом множестве, что оставляет любой элемент набора неизменен в сочетании с ним.

0 голосов
/ 07 мая 2019

Чтобы предотвратить переполнение int, я бы рекомендовал использовать Math.multiplyExact() для умножения. Чтобы предотвратить IndexOutOfBoundsException s, вы должны сначала отфильтровать индексы:

int newNumber = indices.stream()
        .filter(i -> i < numbers.size())
        .mapToInt(numbers::get)
        .reduce(Math::multiplyExact)
        .orElseThrow();

Если вы все равно хотите умножить числа, вам следует сопоставить их с длинными значениями:

long nNumber = indices.stream()
        .filter(i -> i < numbers.size())
        .mapToLong(numbers::get)
        .reduce(Math::multiplyExact)
        .orElseThrow();

В качестве альтернативы orElseThrow() вы можете использовать orElse(), если хотите вернуть значение по умолчанию для пустого потока.

Чтобы удалить индексы из массива numbers, вы можете использовать это:

indices.stream()
        .filter(i -> i < numbers.size())
        .sorted(Comparator.reverseOrder())
        .mapToInt(i -> i)
        .forEach(numbers::remove);
0 голосов
/ 07 мая 2019

Удалить индекс из списка номеров с индексами списка.

List<Integer> newNumbers = numbers.stream().filter(num ->           
            !indices.contains(numbers.indexOf(num)) 
    ).collect(Collectors.toList());
0 голосов
/ 07 мая 2019

При условии, что индексы отсортированы в обратном порядке , один конвейер для обеих ваших операций с использованием последовательного потока может быть:

int product = indices.stream().sequential()
        .mapToInt(index -> numbers.remove((int) index))
        .reduce(1, (a, b) -> a * b);

Примечание :использование List.remove здесь относится к удалению элемента из индекса, а не объекта и, следовательно, приведению к (int).

...