Pulizia di un elenco di dati in Java8


11

Per la pulizia di un elenco di dati, ho creato un metodo che accetta l'elenco di dati e l'elenco delle operazioni di pulizia da eseguire.

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;
}

Il problema qui è che stiamo creando di nuovo l'intero elenco poiché Collectors.toList()restituisce un nuovo elenco. Possiamo ottenere lo stesso risultato senza usare lo spazio extra?

Di seguito è riportato il codice per l'invocazione:

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()restituisce un Collectornon a List, e no: non puoi avere "dati extra" senza "spazio extra"
xerx593

Risposte:


10

Se la modifica dell'elenco sul posto è consentita, è possibile utilizzare

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;
}

andThencombina due Functionistanze e se era presente almeno una funzione, ovvero l' cleanOpselenco non è vuoto, la funzione combinata risultante verrà applicata a tutti gli elementi dell'elenco e agli elementi sostituiti dal risultato, utilizzando replaceAll.

Sfortunatamente, replaceAllrichiede un UnaryOperator<T>anziché un Function<T,T>, nonostante sia funzionalmente equivalente, quindi dobbiamo usare l'adattatore f::apply.

Poiché questi tipi di funzioni sono equivalenti, potremmo cambiare l'elenco in List<UnaryOperator<T>>, ma poi, dobbiamo affrontare il fatto che non esiste andThenun'implementazione specializzata per UnaryOperator, quindi avremmo bisogno di:

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;
}

La fonte del chiamante cambia in

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));

poi.

Come nota a margine, non è necessario un costrutto simile

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

poiché il toString()metodo di a Listproduce esattamente lo stesso output. Dal momento che il println(Object)metodo chiama toString()implicitamente, puoi semplicemente usare

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

7

Sembra che tu debba usare List.replaceAll(), che sostituisce ogni elemento di questo elenco con il risultato dell'applicazione dell'operatore dato a quell'elemento.

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;
}

Rinominerei il metodo, tuttavia, poiché è generico, quindi non elabora necessariamente una Listdi Strings.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.