【问题标题】:Remove duplicates ArrayList custom object [duplicate]删除重复的 ArrayList 自定义对象 [重复]
【发布时间】:2015-07-10 00:03:42
【问题描述】:

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

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

我该如何解决这个问题?

【问题讨论】:

  • 你试过用HashSet代替ArrayList吗?
  • 您是否有任何类似名称和相同时间戳的情况,并且您想将其也保存在列表中?
  • 您必须保留哪些事件?第一次找到?
  • 请点击此链接here。这显示了列表的替代方案。如果可能的话,你可以走这条路。否则评论
  • 为什么这被标记为重复?重复的链接没有回答问题,只是其中的一小部分,并且根据另一部分做错了。我引用:“我想删除具有相同名称但不同时间戳的重复项,并将它们放在另一个列表中。”。似乎过滤甚至不是这里的实际目标:“这样用户可以点击具有该名称的事件,然后选择一个日期。”跨度>

标签: java arraylist duplicate-removal


【解决方案1】:

如果您已经有自己的 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);
}

【讨论】:

  • 我认为这不是完整的解决方案。 我想删除具有相同名称但时间戳不同的重复项,并将它们放在另一个列表中您还必须检查时间戳是否相等
  • 他有一个 equals 方法来检查两个参数,他需要从列表中删除相同命名的事件: OP 说:我想删除具有相同名称但时间戳不同的重复项 i> 这就是我的方法所做的......
  • 是的,但由于 ArrayList 可以包含重复项,因此条件应该是 if (e.getName().equals(event.getName() || e.equals(event)) 以删除具有相同名称和时间戳的不同对象
  • 其实它违背了自然逻辑,但它是真的......很好的捕捉!
  • 非常感谢,这解决了我的问题!!
【解决方案2】:

我认为您使用了错误的数据结构。您想使用Map 的实现并将String(名称)映射到Set&lt;Event&gt;(唯一事件)。

这是我们如何测试它:

  1. 创建一些事件。
  2. 创建Map&lt;String, Set&lt;Event&gt;。这将使我们能够将名称映射到独特事件。
  3. 填写映射。

首先,我们创建一个要测试的事件集合:

    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)));
        }
    };

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

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

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

    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);

    }

检查我们得到了什么:

    System.out.println(eventsByName);

输出:

{
    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]
    ]
}

提示 1:

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

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

输出:

[SecondCategory, FirstCategory]

提示 2:

如果这不是您所期望的,并且您想要不同的唯一性定义,您可以实现 Comparator&lt;Event&gt; 并将其与 TreeSet&lt;Event&gt; 一起使用,而不是使用无法接受自定义 @ 的 HashSet&lt;Event&gt; 987654337@.

如果你有课:

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

这就是填充映射时需要做的所有事情:

    // 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);

    }

祝你好运。

【讨论】:

  • 感谢您的全面回答。如果我从一开始就使用地图会容易得多。另一个答案解决了我的问题,但我会记住 Map 以备将来使用。我现在将使用 Map 将同一事件与多个时间戳联系起来。
  • 现在阻止您使用正确解决方案的任何因素,如果您添加更多基于错误实现的代码,只会变得更糟。使用正确的工具可以使代码更易于维护、测试和理解。如果此答案缺少您想要完成的内容,请将其添加到您的问题中,我可以尝试扩展答案以包含它。
【解决方案3】:

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

【讨论】:

  • OP 必须将 equals 用于其他目的...请仔细阅读
猜你喜欢
  • 2015-12-22
  • 2015-02-22
  • 2016-06-17
  • 2013-12-24
  • 2017-08-02
  • 2018-12-15
  • 1970-01-01
  • 1970-01-01
  • 2015-08-25
相关资源
最近更新 更多