7

在开始之前,我认为这个问题有一个非常简单的答案,我只是忽略了。我想多看几眼手头的问题就能很快指出我的问题。

我有两个 ArrayList,我想比较它们并从中删除重复项。第一个ArrayListArrayList旧信息,而第二个ArrayList包含新信息。

像这样

ArrayList<Person> contactList = new ArrayList();
contactList.add(new Person("Bob");
contactList.add(new Person("Jake");
contactList.add(new Person("Joe");
ontactList.add(new Person("Rob");

ArrayList<Person> updatedContactList = new ArrayList();
updatedContactList.add(new Person("Bob");
updatedContactList.add(new Person("Jake");
updatedContactList.add(new Person("Joe");
updatedContactList.add(new Person("Phil");

我的Person课很简单,只为这个例子创建

public class Person {
    private String name;

    public Person(String a_name) {
        name = a_name;
    }

    public String getName() {
        return name;
    }
}

因此,使用上面的示例,我想删除所有重复项。如果可能的话,我试图将它保留在两个 ArrayList 中,但如果必须的话,我愿意对其中一个 ArrayList 进行深度克隆。

ArrayList因此,一旦比较完成,我希望结果中包含以下信息

contactList           //removed Person
    - Rob

updatedContactList    //new Person
    - Phil

这是我放在一起的代码

for(int i = 0; i < contactList.size(); i++) {
    for(int j = 0; j < updatedContactList.size(); j++) {

        if(contactList.get(i).getName().equals(updatedContactList.get(j).getName())) {
            //removed friends                    
            contactList.remove(contactList.get(i));

            //new friends ---- only one at a time works
            //updatedContactList.remove(updatedContactList.get(j));
        }
    }
}

我只能从上述循环中的一个 ArrayLists 中删除一个人,否则我会得到不正确的结果。

所以我的问题是,有没有一种简单的方法可以从两个 ArrayLists 中删除重复的元素?如果是这样,我该怎么做。

我意识到我可能可以深度克隆更新ArrayList的对象并从中删除对象,但我想知道是否有一种方法无需克隆它。

我也意识到我可以将所有元素填充到一个 Set 中,它会删除重复项,但我想将“已删除”和“新”Person 对象分开。

4

5 回答 5

7

您真正拥有的不是列表,而是集合:将旧联系人和新联系人建模为Set. 还为您的班级实施equals并确保正确操作。hashCodePerson

一旦你有了它,你就可以编写单行代码来计算集合差异(这是你需要的):

final Set<Person> contactsBackup = new HashSet<>(contacts);
contacts.removeAll(updatedContacts);
updatedContacts.removeAll(contactsBackup);

请注意,这涉及再制作一份副本,但它不是深度复制——仅复制引用。这是一个非常轻量级的操作,您不必担心它的影响。

如果出于某种对我来说并不明显的原因,您确实需要列表,那么相同的代码也适用于它们(List也定义了removeAll),但是您将不得不忍受此操作对列表所需的 O(n 2 ) 复杂性。

于 2013-06-03T18:55:46.723 回答
3

在你的课堂上覆盖equals()and并简单地做:hashCode()Person

Set<Person> temp = new HashSet<>(contactList);
contactList.removeAll(updatedContactList);
updatedContactList.removeAll(temp);
temp.clear(); // not necessary if this code is in a method
于 2013-06-03T18:50:56.243 回答
2

从. Set_ addAll_ArrayLists

Set<Person> set = new ArrayList<Person>();

http://docs.oracle.com/javase/6/docs/api/java/util/Set.html

于 2013-06-03T18:47:54.360 回答
1

在这种情况下,如果可能,请使用 Set 而不是 List(如果您使用 Hibernate 从 DB 获取数据,则使用此选项)。然后,您可以在 person 类中重写 equals 和 hashcode 方法,以便在添加所需的比较时可以进行并删除重复项。LinkedHashSet 可以用作列表随着数据的增长而变慢。

于 2013-06-03T19:05:35.007 回答
1

这是利用 Java 8 功能的单行优雅解决方案

public static final <T> void removeCommonEntries(Collection<T> a, Collection<T> b){
        b.removeIf(i -> a.remove(i));
}

我习惯将此解决方案放在自定义的CollectionUtils.

于 2018-01-25T23:03:49.510 回答