Как убрать дубликаты максимума и минимума за один стрим

Я хочу удалить только дубликаты максимальных и минимальных значений из набора целых чисел, возможно ли сделать за один стрим.

IntSummaryStatistics stats = values.stream()
        .mapToInt(Integer::intValue)
        .summaryStatistics();
 
List<Integer> collection = values.stream()
        .filter(integer -> integer > stats.getMin() && integer < stats.getMax())
        .collect(Collectors.toList());
collection.add(stats.getMax());
collection.add(stats.getMin());

Ответы (1 шт):

Автор решения: Nowhere Man

Существующий функционал стримов не слишком подходит, понадобится написать собственный коллектор в объект наподобие IntSummaryStatistics, в котором следовало бы "собирать" списки максимумов, минимумов и промежуточных значений по отдельности, и затем объединить такие списки.

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

static <T extends Comparable<T>> List<T> filterDupMinMax(Collection<T> data) {
    List<T> mins = new ArrayList<>();
    List<T> maxs = new ArrayList<>();
    List<T> mids = new ArrayList<>();

    T min = null;
    T max = null;

    for (T n : data) {
        if (null == min) {
            min = n;
            mins.add(n);
        } else if (min.compareTo(n) >= 0) {
            if (min.compareTo(n) > 0) {
                if (null == max) {
                    max = min;
                    maxs.add(min);
                } else {
                    mids.addAll(mins);
                }
                mins.clear();
                min = n;
            }
            mins.add(n);
        } else {
            if (null == max) {
                max = n;
                maxs.add(n);
            } else if (max.compareTo(n) <= 0) {
                if (max.compareTo(n) < 0) {
                    mids.addAll(maxs);
                    maxs.clear();
                    max = n;
                }
                maxs.add(n);
            } else {
                mids.add(n);
            }
        }
    }
    // отладочный вывод
    System.out.println("mins=" + mins);
    System.out.println("maxs=" + maxs);
    System.out.println("mids=" + mids);

    List<T> result = new ArrayList<>(mids);
    if (!mins.isEmpty()) result.add(mins.get(0));
    if (!maxs.isEmpty()) result.add(maxs.get(0));

    return result;
}

Тест:

List<Integer> data = Arrays.asList(4, 2, 5, 5, 3, 1, 2, 1, 5);

System.out.println("result: " + filterDupMinMax(data));

Результат:

mins=[1, 1]
maxs=[5, 5, 5]
mids=[4, 3, 2, 2]
result: [4, 3, 2, 2, 1, 5]
→ Ссылка