Java流的列表差异

时间:2017-08-09 10:12:58

标签: java list java-8 compare java-stream

我有一个Item类,其中包含字段date,id和action。在我的情况下,我有旧项目列表和另一个列表,其中包括旧项目和新项目,所以我想过滤掉旧项目,所以我不会介意它们。例如,我迭代新项目,只使用那些不属于旧项目列表的项目。

使用for循环它看起来像这样,但我想以功能方式重写它

    List<Item> filteredList = new ArrayList<>();
    for (Item item : newList) {
        for (Item oldItem : oldList) {
            if (!item.getDate().equals(oldItem.getDate()) && !item.getId().equals(oldItem.getId()) && !item.getAction().equals(oldItem.getAction())) {
                filteredList.add(item);
            }
        }
    }

3 个答案:

答案 0 :(得分:3)

首先,我建议在equals课程中实施Item方法,以避免这种复杂的情况(我不确定是否正确,BTW)。

其次,为了提高搜索效率,请将旧列表的元素放在HashSet中,以便进行恒定时间查找。这将需要覆盖equals类的hashCodeItem

最后,代码将如下所示:

List<Item> filteredList = 
    newList.stream()
           .filter(i -> !oldList.contains(i)) // oldList should be replaced with a HashSet 
                                              // for better performance
           .collect(Collectors.toList());

使用HashSet

Set<Item> oldSet = new HashSet<>(oldList);
List<Item> filteredList = 
    newList.stream()
           .filter(i -> !oldSet.contains(i)) 
           .collect(Collectors.toList());

关于你的情况:

if (!item.getDate().equals(oldItem.getDate()) && !item.getId().equals(oldItem.getId()) && !item.getAction().equals(oldItem.getAction()))

看似错误,因为如果两个具有不同ID的项目具有相同的日期(或操作),则它们将无法通过测试。

我相信你打算写:

if (!item.getDate().equals(oldItem.getDate()) || !item.getId().equals(oldItem.getId()) || !item.getAction().equals(oldItem.getAction()))

这意味着如果两个项目中至少有一个属性不同,则认为两个项目彼此不同。

答案 1 :(得分:2)

首先,您应该在equals()类中实现.hashCode()方法(以及Item),这样您就可以正确地比较项目,例如在使用时需要{ {1}} .contains() method

然后,您可以使用List方法测试.contains()中是否存在当前项目,并根据该结果过滤项目。

使用Java 8,您的代码应如下所示:

oldList

注意:

请注意,此处使用List<Item> result = newList.stream() .filter(line -> !oldList.contains(line)) .collect(Collectors.toList()); 并不是必需的,因为您可以使用stream方法实现此目的,例如.retainAll(),这样您就可以过滤List以更好的方式。

答案 2 :(得分:1)

此任务不需要流。只需使用List.removeAll方法,它可以完全符合您的要求:

oldList.removeAll(newList);

这需要Item类来实现equals()方法,以便可以比较元素的相等性并将其删除。

如果您不想改变原始oldList,可以创建一个新列表,然后从中删除元素:

List<Item> filteredList = new ArrayList<>(oldList);
filteredList.removeAll(newList);

另一种更实用的 ish 方法是使用Collection.removeIf方法:

oldList.removeIf(item -> newList.contains(item));

或者只是:

oldList.removeIf(newList::contains);

这仍然需要Item类来实现equals()方法。但是,它也会效率低下,因为List.contains需要遍历整个newList以检查oldList的每个项目是否属于它。更有效的方法是使用HashSet

Set<Item> newSet = new HashSet<>(newList);

然后,如上所述使用removeIf

oldList.removeIf(newSet::contains);

这种方法不仅要求Item类实现equals()方法,还需要hashCode方法,该方法必须符合Object类合同。平等。