本问题已经有最佳答案,请猛点这里访问。
我有一个arraylist,它包含类Event的元素。事件有两个属性,Name和Timestamp。列表现在显示所有事件。我想删除具有相同名称但时间戳不同的重复项,并将它们放在另一个列表中。这样,用户可以单击具有该名称的事件,然后选择日期。
对于我的应用程序中的其他一些功能,我已经重写了equals函数(用于比较名称和时间戳)。
我怎么解决这个问题?
您是否尝试使用hashset而不是arraylist?
您是否有类似相同名称和时间戳的情况,并且希望将其也保存在列表中?
你必须保留哪些活动?第一次发现?
请点击这里的链接。这将显示列表的备选方案。如果可能的话,你可以走这条路。其他注释
为什么这个标记为副本?复制链接没有回答这个问题,只回答了一小部分,而基于另一部分,它做得不对。我引用:"我想删除具有相同名称但时间戳不同的重复项,并将它们放在另一个列表中。"这里的过滤似乎并不是真正的目标:"这样用户就可以点击一个具有该名称的事件,然后选择一个日期。"
如果您已经有了自己的equals方法,则不能使用Hash集合。必须手动检查它是否实现了嵌套循环:
List allEvents = // fill with your events.
List noRepeat = new ArrayList();
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);
}
我认为这不是完整的解决方案。我想删除具有相同名称但时间戳不同的重复项,并将它们放在另一个列表中,您还需要检查timmestamps是否相等
他有一个equals方法来检查两个参数,他需要从一个列表中删除相同的命名事件:op说:我想删除具有相同名称但时间戳不同的重复项,这就是我的方法所做的……
是的,但是由于ArrayList可以包含重复条件,所以应该是if (e.getName().equals(event.getName() || e.equals(event))来删除同样具有相同名称和时间戳的不同对象。
事实上,这违背了自然的逻辑,但这是真的…好抓!
@jordicastilla一个很好的方法就是使用自定义的Comparator与TreeSet进行比较(使用该比较器创建一个集合)。它还加强了清晰性,因为使用正确的接口传达了这个想法。见我答案的最后一部分。
非常感谢,这解决了我的问题!!
我认为您使用的数据结构错误。您希望使用Map的实现,并将String(名称)映射到Set(唯一事件)。
下面是我们测试它的方法:
创建一些事件。
创建Map。这将允许我们将名称映射到唯一的事件。
填充映射。
因此,首先,我们创建一组要测试的事件:
Collection events = new ArrayList() {
/**
*
*/
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> eventsByName = new HashMap>();
现在,我们用每个名称的唯一事件填充映射:
for (Event e : events) {
if (!eventsByName.containsKey(e.getName())) {
// create new set by name
eventsByName.put(e.getName(), new HashSet());
}
// 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,并将其与TreeSet一起使用,而不是使用不能接受自定义Comparator的HashSet。
所以如果你有一门课:
class EventByRandomDefinitionComparator implements Comparator{
// implementation ...
}
这是填充映射时需要完成的全部工作:
// create different comparison mechanism
Comparator 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(comparator)));
}
// add event to existing Set.
// duplicates will be dropped since it's a `Set`
eventsByName.get(e.getName()).add(e);
}
祝你好运。
谢谢你的综合回答。如果我从一开始就用地图的话会容易得多。另一个答案解决了我的问题,但我会把地图记在心里,以备将来使用。我现在将使用一个映射将同一事件与多个时间戳链接起来。
无论是什么阻止你现在使用正确的解决方案,如果你添加更多基于错误实现的代码,情况会更糟。使用正确的工具可以使代码更容易维护、测试和理解。如果这个答案缺乏你想要完成的事情,那就把它添加到你的问题中,我可以尝试扩展这个答案来包含它。
您应该在事件类中重写您的equals()和hashCode()方法,并将所有对象添加到Set而不是List中。如果您正确地覆盖了equals()和hashCode(),Set将不允许复制对象。
为了另一个目的必须使用equals…请仔细阅读