การล้างรายการข้อมูลใน 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กรณีและถ้าอย่างน้อยหนึ่งฟังก์ชั่นในปัจจุบันคือรายการไม่ว่างที่เกิดฟังก์ชั่นรวมกันนี้จะนำไปใช้กับองค์ประกอบของรายการและองค์ประกอบแทนที่ด้วยผลการใช้cleanOpsreplaceAll

แต่น่าเสียดายที่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()วิธีการของการ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ของStrings

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.