Список возврата <Integer>из метода в Java 8? - PullRequest
0 голосов
/ 14 ноября 2018

У меня есть следующий метод (см. Ниже). Код работает, но я получил комментарии, что есть много повторений и что я должен использовать IntStream.

Не могли бы вы указать, как лучше оптимизировать код? Заранее спасибо.

public static List<Integer> oddOrEven(List<Integer> integers) {
    long sum = integers.stream().mapToInt(i ->i).summaryStatistics().getSum();
    if (sum % 2 == 0) {
        return integers.stream().filter(x -> x % 2==0).distinct().collect(Collectors.toList());
    } else if (sum % 2 != 0) {
        return integers.stream().filter(x -> x % 2 != 0).distinct().collect(Collectors.toList());
    }
    return null;
}

Ответы [ 4 ]

0 голосов
/ 14 ноября 2018

Я дам вам более простое решение, которое использует стандартные языковые конструкции Java, не создавая другие объекты-паразиты, которые создают потоки.Я не говорю, что потоки плохие.Я хочу сказать, что если вы передадите List методу и вернете List, тогда преобразование в поток и сбор обратно в список - это дополнительная работа, которая вам не нужна, и вы не должны этого делать.Вы можете попробовать его в образовательных целях и для изучения потоков, но в данном конкретном случае вы просто теряете производительность, и если вы начнете делать это таким образом везде в реальном приложении, это сложится, и это может стать значительной проблемой.Несмотря на то, что преждевременная оптимизация - это нехорошо, то же самое можно сказать и о том, чтобы делать все с потоками только потому, что они находятся в Java и вообще не заботятся о производительности.

Если у нас четное число нечетных чисел, то сумматоже чётно.Итак, вот код с побитовыми операторами (просто для удовольствия - вы можете написать его со стандартным i% 2 и т. Д.):

public static Collection<Integer> oddOrEven(List<Integer> integers) {
    int mod = 0;
    for (Integer i : integers) {
        if((i & 1) == 1) mod=mod^1;
    }
    Set<Integer> result = new HashSet<>();
    for (Integer i : integers){
        if (((i & 1) ^ mod)==0)     
           result.add(i);

      }
  return result; //Converting to set because we want distinct results.
                 // If the order is important we can use treeset or convert to list
}

Вы можете провести некоторое тестирование с другими решениями, основанными на Stream.Решение, использующее стандартную Java-конструкцию без дополнительной перегрузки, будет в большинстве случаев такой же скоростью или быстрее.Например, использование карты - это хорошо, но с большим списком с большим количеством повторяющихся чисел в какой-то момент количество столкновений может сделать его во много раз медленнее, чем другими способами.Сложность всех алгоритмов линейна, но объем работы за одну итерацию может варьироваться в зависимости от различных потоковых решений (а также от подхода старой школы), и если кто-то не знает, что за потеря, может быть, прилипает к хорошо известным иЛегко предсказать сценарий лучше.

0 голосов
/ 14 ноября 2018
 long sum = integers.stream().reduce(0, (u, v) -> u + v);
 return integers.stream().filter(x -> (x % 2)==(sum % 2)).distinct().collect(Collectors.toList());
0 голосов
/ 14 ноября 2018
public static List<Integer> oddOrEven(List<Integer> integers) {
    Function<Integer, Integer> fun =  i -> i%2;
    Map<Integer, List<Integer>> map = integers.stream().collect(Collectors.groupingBy(fun));        
    return map.get(1).size()%2 == 0? map.get(0): map.get(1);
}
0 голосов
/ 14 ноября 2018

Похоже, вам нужна только сумма элементов, чтобы проверить, является ли она нечетной или четной. Чтобы знать это, достаточно проверить, является ли количество нечетных элементов нечетным или четным.

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

public static List<Integer> oddOrEven(List<Integer> integers) {
    Map<Boolean,List<Integer>> 
        oddsAndEvens = integers.stream()
                               .collect(Collectors.partitioningBy(i->i%2==0));
    return oddsAndEvens.get(false).size() % 2 == 0 ? // check if there's an even number of odd
                                                     // elements, which means the sum is even
           oddsAndEvens.get(true) : // return the even elements
           oddsAndEvens.get(false); // return the odd elements
}

Тестирование:

System.out.println (oddOrEven(Arrays.asList (1,2,3,4,5)));
System.out.println (oddOrEven(Arrays.asList (1,2,3,4,5,3)));

Выход:

[1, 3, 5]
[2, 4]

EDIT:

В своем первоначальном ответе я пропустил шаг distinct(), который должен быть выполнен после того, как мы решим, следует ли возвращать нечетные или четные элементы. Боюсь, это требует добавления второго Stream конвейера:

public static List<Integer> oddOrEven(List<Integer> integers) {
    Map<Boolean,List<Integer>> 
        oddsAndEvens = integers.stream()
                               .collect(Collectors.partitioningBy(i->i%2==0));
    return oddsAndEvens.get(false).size() % 2 == 0 ?
           oddsAndEvens.get(true).stream().distinct().collect(Collectors.toList()) :
           oddsAndEvens.get(false).stream().distinct().collect(Collectors.toList());
}

или (с предложением Хольгера):

public static List<Integer> oddOrEven(List<Integer> integers) {
    Map<Boolean,List<Integer>> 
        oddsAndEvens = integers.stream()
                               .collect(Collectors.partitioningBy(i->i%2==0));
    return oddsAndEvens.get(oddsAndEvens.get(false).size() % 2 == 0)
                       .stream()
                       .distinct()
                       .collect(Collectors.toList());
}
...