【问题标题】:Cleaning a list of data in Java8在 Java8 中清理数据列表
【发布时间】:2019-12-03 10:29:39
【问题描述】:

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

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,并且不:没有“额外空间”就不能拥有“额外数据”

标签: java java-8 functional-programming java-stream


【解决方案1】:

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

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&lt;T&gt; 而不是 Function&lt;T,T&gt;,尽管在功能上是相同的,所以我们必须使用适配器 f::apply

由于这些函数类型是等价的,我们可以将列表更改为List&lt;UnaryOperator&lt;T&gt;&gt;,但是,我们不得不面对UnaryOperator没有专门的andThen实现的事实,所以我们需要:

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

因为ListtoString() 方法产生完全相同的输出。由于println(Object) 方法隐式调用toString(),你可以直接使用

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

【讨论】:

    【解决方案2】:

    您似乎需要使用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;
    }
    

    不过,我会重命名该方法,因为它是通用的,因此它不一定会处理 ListStrings。

    【讨论】:

      猜你喜欢
      • 2017-04-30
      • 2020-09-02
      • 2019-07-02
      • 2019-04-10
      • 2010-09-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-10-26
      相关资源
      最近更新 更多