在 Java8 中清理数据列表

Dha*_*ari 10 java functional-programming java-8 java-stream

为了清理数据列表,我创建了一个接受数据列表和要执行的清理操作列表的方法。

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;
}
Run Code Online (Sandbox Code Playgroud)

这里的问题是我们在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()));
}
Run Code Online (Sandbox Code Playgroud)

Hol*_*ger 9

如果允许就地修改列表,则可以使用

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;
}
Run Code Online (Sandbox Code Playgroud)

andThen组合两个Function实例,如果至少存在一个函数,即cleanOps列表不为空,则生成的组合函数将应用于所有列表元素和结果替换的元素,使用replaceAll.

不幸的是,尽管功能等效,但replaceAll需要 aUnaryOperator<T>而不是 a 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;
}
Run Code Online (Sandbox Code Playgroud)

调用者的源更改为

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));
Run Code Online (Sandbox Code Playgroud)

然后。

作为旁注,不需要像

System.out.println(Arrays.toString(cleanData(data, cleanOps).toArray()));
Run Code Online (Sandbox Code Playgroud)

因为 a 的toString()方法List产生完全相同的输出。由于该println(Object)方法toString()隐式调用,您可以只使用

System.out.println(cleanData(data, cleanOps));
Run Code Online (Sandbox Code Playgroud)


Era*_*ran 6

看起来您需要使用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;
}
Run Code Online (Sandbox Code Playgroud)

不过,我会重命名该方法,因为它是通用的,所以它不一定处理 a Listof Strings。