【问题标题】:How to compare elements of a list using streams?如何使用流比较列表的元素?
【发布时间】:2020-03-02 23:57:11
【问题描述】:

例如,我需要遍历自定义列表List<Model> 并比较其中的项目。所以使用for 循环它看起来像这样

for(int i = 0; i < list.size()-1; i++) {
    for (int j = i + 1; j < list.size(); j++) {
        if (list.get(i).getSomeItem().equals(list.get(j).getSomeItem()){
                /*modify the list using*/
                list.get(j).setSomeOtherItem(list.get(i).getSomeItem()+list.get(j).getSomeItem());
        }
    }
}

但是如何使用流或 forEach() 获得相同的结果?我正在尝试制作这样的东西

for (Model i : list){
    for (Model j : list){
        if(i.getSomeItem.equals(j.getSomeItem()){
            /*same logic as in for loop*/
        }
    }
}

或者这个

 List<StorageModel> newList = list.stream()
           .filter(item -> item.getSomeItem.equals...)

所以问题是forEach 两个循环都从同一个元素开始并比较相同的项目。对于流,我不知道如何获得下一个值。有什么办法吗?

【问题讨论】:

  • 真正重要的是 "some logic" 是什么,通过流实现它。否则,无论如何,你最好使用 for 每次迭代。
  • 好吧,我的错!我会删除它。
  • 为什么要用流的东西替换使用传统 for 循环的工作代码?仅仅因为你使用的是 Java8 或更高版本,并不意味着一切都应该重写。
  • @Eritrean 我正在尝试学习新事物,我认为这个问题会很有趣:)
  • 您想将ii+1 元素或i 与列表中的其余元素进行比较吗? @SauliusMeidus

标签: java for-loop arraylist foreach java-stream


【解决方案1】:

了解 Java 提供的流式 API 不仅是一种 API,而且还是一种不同的编程范式,这一点非常重要。当您使用流时,您需要接受范式。 你告诉流你想达到什么目标,而不是你想如何实现它。而且,与许多其他事情一样,使用流并不总是最好的解决方案。有时,使用普通的老式 foo 循环会使代码更易于阅读,并且可能性能也更好。

使用流

如果你想在这个例子中使用流,你可以做类似下面的事情。

据我所知,您正在尝试查找(基于某些标准)相同的元素。换句话说,您希望根据Model 对象的属性值对元素进行分组。

假设我们的Model 类如下所示:

public class Model {
    private int id;
    private String name;

    public Model(int id, String name) {
        this.id = id;
        this.name = name;
    }

    public int getId() {
        return id;
    }

    public String getName() {
        return name;
    }
}

下面的示例显示了如何根据名称对模型列表中的元素进行分组。

import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

public class CompareItems {

    public static void main(String[] args) {
        List<Model> items = Arrays.asList(
                new Model(1, "model_1"), new Model(2, "model_2"), new Model(3, "model_1"),
                new Model(4, "model_3"), new Model(5, "model_2"), new Model(6, "model_2"));

        Map<String, Set<Integer>> result = 
                items.stream()
                .collect(Collectors.groupingBy(Model::getName, Collectors.mapping(Model::getId, Collectors.toSet())));

        System.out.println(result);
    }
}

当你打印result 对象时,你会得到这个:

{model_1=[1, 3], model_3=[4], model_2=[2, 5, 6]}

result 对象中,您有模型的名称和所有同名模型对象的 ID。

然后,根据您要执行的操作,您可以通过迭代 result 对象将更改应用到每个组。

【讨论】:

    【解决方案2】:

    这种情况你可以试试reduce方法。

    list.stream().reduce((Item a, Item b)->{
            if(a.equals(b)){
                a.setValue(a.getValue()+b.getValue());
            }
            return b;
        });
    

    【讨论】:

      【解决方案3】:

      如果你有两个ArrayLists A和B,你可以得到

      • A + B 与 A.addAll(B)
      • A - B 与 A.removeAll(B)
      • A ∩ B 与 A.retainAll(B)
      • A ∪ B 复制 A 到 Set A' 然后 A'.addAll(B)

      然后,如果需要,您可以使用流来处理结果。但是,获得您感兴趣的所需子集(例如共同的项目或 A ∩ B)确实不是我会考虑使用流做的事情。

      【讨论】:

        猜你喜欢
        • 2018-05-30
        • 1970-01-01
        • 1970-01-01
        • 2020-02-21
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-08-15
        相关资源
        最近更新 更多