Membersihkan daftar data di Java8

11

Untuk membersihkan daftar data, saya telah membuat metode yang menerima daftar data dan daftar operasi pembersihan yang harus dilakukan.

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

Masalahnya di sini adalah bahwa kami membuat seluruh daftar lagi sebagai Collectors.toList()mengembalikan daftar baru. Bisakah kita mencapai hasil yang sama tanpa menggunakan ruang ekstra?

Di bawah ini adalah kode untuk doa:

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()));
}
Dharmvir Tiwari
sumber
toList()mengembalikan Collectorbukan List, dan tidak: Anda tidak dapat memiliki "data ekstra" tanpa "ruang ekstra"
xerx593

Jawaban:

10

Jika memodifikasi daftar di tempat diperbolehkan, Anda bisa menggunakan

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

andThenmenggabungkan dua Functioninstance dan jika setidaknya satu fungsi hadir, yaitu cleanOpsdaftar tidak kosong, fungsi gabungan yang dihasilkan akan diterapkan ke semua elemen daftar dan elemen diganti dengan hasil, menggunakan replaceAll.

Sayangnya, replaceAllmembutuhkan yang UnaryOperator<T>alih - alih Function<T,T>, meskipun secara fungsional setara, jadi kita harus menggunakan adaptor f::apply.

Karena tipe fungsi ini setara, kita dapat mengubah daftar List<UnaryOperator<T>>, tetapi kemudian, kita harus menghadapi kenyataan bahwa tidak ada andThenimplementasi khusus untuk UnaryOperator, jadi kita perlu:

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

Sumber pemanggil berubah menjadi

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

kemudian.

Sebagai catatan, tidak perlu untuk membangun seperti

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

sebagai toString()metode dari Listmenghasilkan output yang persis sama. Karena println(Object)metode ini memanggil toString()secara implisit, Anda bisa menggunakannya

System.out.println(cleanData(data, cleanOps));
Holger
sumber
7

Sepertinya Anda perlu menggunakan List.replaceAll(), yang menggantikan setiap elemen dari daftar ini dengan hasil menerapkan operator yang diberikan ke elemen itu.

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

Aku akan mengubah nama metode, meskipun, karena itu generik, sehingga tidak selalu memproses Listdari Strings.

Eran
sumber