【问题标题】:Java : Dirty Check for ArrayList?Java:ArrayList 的脏检查?
【发布时间】:2018-04-30 08:05:39
【问题描述】:

如何在 Java 中对 ArrayList 执行脏检查?

我有一个对象

Animal
{
    String animalName;
    String animalType;
    String animalPlace
}

我有两个列表:

List<Animal> animalList1 = new ArrayList<Animal>();
List<Animal> animalList2 = new ArrayList<Animal>();

在第一个列表中, 我有价值观:

[0][lion,Carnivorous,Africa]
[1][tiger,Carnivorous,Zambia]
[2][Goat,Herbivorous,Zimbabwe]

在第二个列表中, 我有价值观:

[0][lion,Carnivorous,Africa]
[1][tiger,Carnivorous,Zambia]
[2][Goat,Herbivorous,Norway]

在第二个列表中, 索引 2 处元素的 animalPlace 已从津巴布韦更改为挪威。 如何比较两个列表值,并且更改的值将该对象放在单独的列表中?

List<Animal> animalList3 = new ArrayList<Animal>();

[0] [Goat,Herbivorous,Norway]

我知道使用 for 循环比较列表的传统方法:

for (int i = 0; i < list1.size(); i++) 
{
  for (int j = i+1; j < list2.size(); j++) 
  {
    // compare list1 and list2 values
  }
}

有没有更快和/或更好的方法?

【问题讨论】:

  • 实现equals() 方法并保留唯一的方法
  • 好吧,看来您想比较 list1[i] 和 list2[i]。这不是您的嵌套循环所做的。正确地做到这一点已经快得多了。从寻找正确的解决方案开始。如果不够快,则进行优化。
  • 正如@azro 所说,实现equals。那么您可以使用以下内容:list1.stream().filter(a -&gt; list2.stream().anyMatch(a2 -&gt; a2.equals(a))).collect(Collectors.toList());
  • @JBNizet 是的,我需要比较两个列表

标签: java arraylist java-8 dirtyread


【解决方案1】:

List#removeAll() 方法是你的朋友。

为 Animal 实现 equals()hashCode(),然后:

List<Animal> animalList3 = new ArrayList<Animal>(animalList2);
animalList3.removeAll(animalList1);

【讨论】:

  • @azro 已在animalList2 中更新的动物不应该在equals() animalList1 中的动物,因此removeAll() 不会从新创建的animalList3 中删除更新的动物.因此,animalList3 将包含所有新的 修改条目。 OP 没有说明是否会存在新条目,以及如果出现该怎么办。同样,OP 没有指定如果条目已被删除该怎么办。但是如果只修改列表中的条目,所有修改的条目都会出现在animalList3中。
【解决方案2】:

您可以这样做:遍历第二个列表并仅保留第一个 list 的那些 等于:它们已经修改(typeplacename 相同)

List<Animal> res = animalList2.stream()
            .filter(a -> animalList1.stream()
                        .anyMatch(b -> !b.equals(a) && b.animalName.equals(a.animalName)))
            .collect(Collectors.toList());

与:

List<Animal> animalList1 = new ArrayList<Animal>();
animalList1.add(new Animal("lion", "Carnivorous", "Africa"));
animalList1.add(new Animal("tiger", "Carnivorous", "Zambia"));
animalList1.add(new Animal("Goat", "Herbivorous", "Zimbabwe"));
animalList1.add(new Animal("Donkey", "Herbivorous", "Zimbabwe"));

List<Animal> animalList2 = new ArrayList<Animal>();
animalList2.add(new Animal("lion", "Carnivorous", "Africa"));  //not new but no modif   X
animalList2.add(new Animal("tiger", "Carnivorous", "Zambia")); //not new but no modif   X
animalList2.add(new Animal("Goat", "Herbivorous", "Norway"));  //not new and modif      V
animalList2.add(new Animal("Horse", "Herbivorous", "Norway")); //new                    X

最后你只会得到[Goat,Herbivorous,Norway],这是唯一一个从第一个列表更新到第二个的列表


你需要一个像这样的equals()

@Override
public boolean equals(Object o) {
    if (this == o) return true;
    if (o == null || getClass() != o.getClass()) return false;
    Animal animal = (Animal) o;
    return animalName.equals(animal.animalName) && animalType.equals(animal.animalType) && animalPlace.equals(animal.animalPlace);
}

【讨论】:

  • 这将只比较新对象还是来自对象的属性?
  • 只打印那些在 both 列表中但在两者中都不相等的,所以那些已经更新的
  • 您假设animalName 是唯一键。如果两个列表都包含 [Goat,Herbivorous,Zimbabwe] 和 [Goat,Herbivorous,Norway],那么这两个条目都将通过您的 anyMatch 过滤器(存在具有该名称的不相等的动物),并且两个条目都将出现在修改后的列表,尽管没有修改存在。
  • 另外,如果您对我的回答投了反对票并添加了解释您反对票的评论,然后您根据我的回复删除了您的评论,那么 a) 删除反对票,或 b) 发布不同的评论解释了为什么你仍然不赞成我的回答。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-03-16
  • 1970-01-01
  • 1970-01-01
  • 2011-02-10
  • 2012-08-04
  • 1970-01-01
相关资源
最近更新 更多