Очищення списку даних у Java8


11

Для очищення списку даних я створив метод, який приймає список даних та перелік операцій очищення, які слід виконати.

public <T> List<T> cleanData(List<T> data, List<Function<T, T>> cleanOps) {
    List<T>dataNew=data.stream().map((str) -> {
        T cleanData = str;
        for(Function<T,T> function:cleanOps) {
            cleanData=function.apply(cleanData);
        }
        return cleanData;
    }).collect(Collectors.toList());
    return dataNew;
}

Проблема тут полягає в тому, що ми знову створюємо весь список, як Collectors.toList()повертаємо новий список. Чи можемо ми досягти такого ж результату, не використовуючи додаткового місця?

Нижче наведено код для виклику:

public void processData() {
    List<Function<String, String>> cleanOps = new ArrayList<>();
    cleanOps.add(String::toLowerCase);
    cleanOps.add(str -> str.replaceAll(" ", ""));
    List<String> data = new ArrayList<>();
    data.add("John Doe");
    data.add("Jane Doe");
    System.out.println(Arrays.toString(cleanData(data, cleanOps).toArray()));
}

toList()повертає а Collectorне а List, і ні: ви не можете мати "додаткових даних" без "додаткового місця"
xerx593

Відповіді:


10

Якщо зміна списку на місці дозволена, ви можете використовувати

public <T> List<T> cleanData(List<T> data, List<Function<T, T>> cleanOps) {
    cleanOps.stream().reduce(Function::andThen).ifPresent(f -> data.replaceAll(f::apply));
    return data;
}

andThenпоєднує два Functionекземпляри, і якщо принаймні одна функція була присутня, тобто cleanOpsсписок не порожній, отримана об'єднана функція буде застосована до всіх елементів списку та елементів, замінених результатом, використовуючи replaceAll.

На жаль, replaceAllпотрібен, UnaryOperator<T>а не а Function<T,T>, незважаючи на функціональний еквівалент, тому ми повинні використовувати адаптер f::apply.

Оскільки ці типи функцій еквівалентні, ми можемо змінити список на List<UnaryOperator<T>>, але тоді нам доведеться зіткнутися з тим, що спеціалізованої andThenреалізації для цього немає UnaryOperator, тому нам знадобиться:

public <T> List<T> cleanData(List<T> data, List<UnaryOperator<T>> cleanOps) {
    cleanOps.stream()
        .reduce((f1,f2) -> t -> f2.apply(f1.apply(t)))
        .ifPresent(data::replaceAll);
    return data;
}

Джерело абонента змінюється на

List<UnaryOperator<String>> cleanOps = new ArrayList<>();
cleanOps.add(String::toLowerCase);
cleanOps.add(str -> str.replaceAll(" ", ""));
List<String> data = new ArrayList<>();
data.add("John Doe");
data.add("Jane Doe");
System.out.println(cleanData(data, cleanOps));

тоді.

Як бічна примітка, немає необхідності в такій конструкції

System.out.println(Arrays.toString(cleanData(data, cleanOps).toArray()));

як toString()метод a Listвиробляє точно такий же вихід. Оскільки println(Object)метод викликає toString()неявно, ви можете просто використовувати

System.out.println(cleanData(data, cleanOps));

7

Схоже, вам потрібно скористатися List.replaceAll(), що замінює кожен елемент цього списку результатом застосування цього оператора до цього елемента.

public <T> List<T> cleanString(List<T> data, List<Function<T, T>> cleanOps) {
    data.replaceAll(str -> {
        T cleanData = str;
        for (Function<T,T> function : cleanOps) {
            cleanData = function.apply(cleanData);
        }
        return cleanData;
    });
    return data;
}

Я б перейменувати метод, хоча, так як це родове, так що це не обов'язково процес А Listз Stringс.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.