java 删除重复的 ArrayList 自定义对象

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/29965140/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-11-02 16:11:04  来源:igfitidea点击:

Remove duplicates ArrayList custom object

javaarraylistduplicate-removal

提问by Nicolas Zawada

I have an ArrayList which contains element of a class Event. Event has two properties, Nameand Timestamp. The list now shows ALL events. I want to remove the duplicates with the same name, but different timestamp, and put them in another list. This way the user can click on an event with that name, then select a date.

我有一个包含类元素的 ArrayList Event。事件有两个属性,NameTimestamp。该列表现在显示所有事件。我想删除具有相同名称但时间戳不同的重复项,并将它们放在另一个列表中。通过这种方式,用户可以单击具有该名称的事件,然后选择一个日期。

I am already overriding the function equals (that compares name AND timestamp) for some other functionalities in my application.

我已经为我的应用程序中的一些其他功能覆盖了函数 equals(比较名称和时间戳)。

How can I solve this?

我该如何解决这个问题?

回答by Jordi Castilla

If you already have your own equals method you can't use Hashcollections. You must manually check it implementing a nested loop:

如果您已经拥有自己的 equals 方法,则不能使用Hash集合。您必须手动检查它是否实现了嵌套循环:

List<Event> allEvents = // fill with your events.
List<Event> noRepeat = new ArrayList<Event>();

for (Event event : allEvents) {
    boolean isFound = false;
    // check if the event name exists in noRepeat
    for (Event e : noRepeat) {
        if (e.getName().equals(event.getName()) || (e.equals(event))) {
            isFound = true;        
            break;
        }
    }
    if (!isFound) noRepeat.add(event);
}

回答by Reut Sharabani

I think you're using the wrong data structure. You want to use an implementation of Mapand map String(name) to Set<Event>(unique events).

我认为您使用了错误的数据结构。您想使用Map和映射String(名称)到Set<Event>(唯一事件)的实现。

Here is how we test it:

下面是我们测试它的方法:

  1. Create some events.
  2. Create Map<String, Set<Event>. this will allow us to map a name to uniqueevents.
  3. Fill the mapping.
  1. 创建一些事件。
  2. 创建Map<String, Set<Event>. 这将允许我们将名称映射到唯一事件。
  3. 填充映射。

So first, we create a collection of events to test:

所以首先,我们创建一个事件集合来测试:

    Collection<Event> events = new ArrayList<Event>() {
        /**
         * 
         */
        private static final long serialVersionUID = 1L;

        {
            add(new Event("FirstCategory", new Timestamp(0)));
            add(new Event("FirstCategory", new Timestamp(0)));
            add(new Event("FirstCategory", new Timestamp(1)));
            add(new Event("SecondCategory", new Timestamp(2)));
        }
    };

Now we create a mapping between a name and all of it's corresponding uniqueevents:

现在我们创建一个名字和它所有对应的唯一事件之间的映射:

    Map<String, Set<Event>> eventsByName = new HashMap<String, Set<Event>>();

Now we fill the mapping with unique events for each name:

现在我们用每个名称的唯一事件填充映射:

    for (Event e : events) {
        if (!eventsByName.containsKey(e.getName())) {
            // create new set by name
            eventsByName.put(e.getName(), new HashSet<Event>());

        }
        // add event to existing Set.
        // duplicates will be dropped since it's a `Set`
        eventsByName.get(e.getName()).add(e);

    }

Check what we got:

检查我们得到了什么:

    System.out.println(eventsByName);

Output:

输出:

{
    SecondCategory=[
        Event [name=SecondCategory, timestamp=1970-01-01 02:00:00.002]
    ],
    FirstCategory=[
        Event [name=FirstCategory, timestamp=1970-01-01 02:00:00.0],
        Event [name=FirstCategory, timestamp=1970-01-01 02:00:00.001]
    ]
}

Tip 1:

提示 1:

To get the list of names you only need to look at the Map's keys, which are effectively a Setas well:

要获取名称列表,您只需查看Map的键,它们实际上也是 a Set

System.out.println(eventsByName.keySet());

Output:

输出:

[SecondCategory, FirstCategory]

Tip 2:

提示 2:

If this isn't what you expect, and you want a different definition of uniqueness, you can implement a Comparator<Event>and use that with a TreeSet<Event>instead of using the HashSet<Event>which can not accept a custom Comparator.

如果这不是您所期望的,并且您想要一个不同的唯一性定义,您可以实现 aComparator<Event>并将其与 a 一起使用,TreeSet<Event>而不是使用HashSet<Event>不能接受自定义的Comparator

So if you have a class:

所以如果你有一堂课:

class EventByRandomDefinitionComparator implements Comparator<Event>{
    // implementation ...
}

This is all that needs to be done when filling the mapping:

这就是填充映射时需要完成的全部工作:

    // create different comparison mechanism
    Comparator<Event> comparator = new EventByRandomDefinitionComparator();

    for (Event e : events) {
        if (!eventsByName.containsKey(e.getName())) {
            // create new set by name
            // changed Set implementation to use new comparator
            eventsByName.put(e.getName(), new TreeSet<Event>(comparator)));
        }
        // add event to existing Set.
        // duplicates will be dropped since it's a `Set`
        eventsByName.get(e.getName()).add(e);

    }

Good luck.

祝你好运。

回答by Aakash

You should override your equals()and hashCode()methods in your Event class and add all the objects in a Setrather than a List. A Setwill not allow the duplicate objects, provided you have properly overridden the equals()and hashCode().

您应该覆盖Event 类中的equals()hashCode()方法,并将所有对象添加到 aSet而不是List. ASet将不允许重复的对象,前提是您已正确覆盖equals()hashCode()