在Java List中合并类似对象的最佳方法是什么?

时间:2015-02-19 16:40:13

标签: java list arraylist compare

这是我的问题(简化):

假设我们有一个班级:

public class MyClass{
String name;
Double amount;
String otherAttribute;
}

List<MyClass> myList

假设我们有来自myList的2个元素。假设 object1 object2

我想做的是:

if (object1.name.equals(object2.name){
//add amount of object2 to object1
//remove object 2 from the list
}

考虑到我有一个很大的列表(可能有100个元素),我想找到最好,耗费更少的方式来做我想做的事。

你会建议什么?


修改

  • 是的100个项目并不大,但我会为许多不同大小的列表多次调用此方法(合并类似对象)。所以我希望找到最好的做法。

  • 遗憾的是,我无法覆盖MyClass的equals或hashCode方法(客户要求)

6 个答案:

答案 0 :(得分:3)

我将对象添加到HashMap中,其中name是键,MyClass是存储的值。遍历列表中的每个对象以将其添加到地图中。如果地图中的名称不是,则只需添加名称,对象对。如果它已在地图中,请将金额添加到已存储的对象中。循环完成后,从地图中提取对象。

答案 1 :(得分:2)

遗憾的是,这是一个O(n ^ 2)问题。您需要将n个元素与n-1个其他元素进行比较。没有办法做到这一点,只能蛮力。

但是,如果使用了HashMap,则可以在将元素添加到Map(这是O(1)操作)之前检查元素的映射。它看起来像这样:

HashMap<String, MyClass> map = new HashMap<String, MyClass>();

添加元素时:

if (map.get(obj1.name) != null) {
    var obj2 = map.get(obj1.name);
    obj2.amount = obj2.amount + obj1.amount;
    map.put(obj1.name, obj2);
}

答案 2 :(得分:1)

对于列表来说,100个元素是一个很小的尺寸,考虑到你不会重复这个操作几十万次。如果是这种情况,我会考虑创建一个数据结构,通过搜索属性(例如Map)索引列表项,或者如果合适并使用有效的搜索算法对其进行排序。

一种方法(如Bill所建议的)将遍历List将每个元素添加到Map,并将name属性作为键。您可以利用put的返回信息来了解先前是否已将name放入地图中,并在当前元素中添加了先前累积的amount。最后,您可以使用values()来获取List而无需重复。

例如:

List<MyClass> l;
Map<String, Myclass> m = new HashMap<MyClass>();
for (MyClass elem : l) { 
    MyClass oldElem = m.put(elem.getName(), elem);
    if (oldElem != null) { 
        elem.setAmount(elem.getAmount() + oldElem.getAmount());
    }
} 
l = new ArrayList<MyClass>(m.values());

如果您需要保留列表中的顺序,请考虑使用LinkedHashMap

答案 3 :(得分:0)

&#39;大&#39;是相对的,100项肯定不大,想象一下你是否必须处理1.000.000项/秒的流。然后你会重新定义大:D

在你的例子中,我认为最好避免的是创建一套你的物品&#39;名。搜索java HashSet需要O(1),所以如果一个对象&#39; name存在于哈希集中,然后在列表中更新它。一个更好的解决方案是创建一个HashMap,你可以说就是这样。

if(mymap.contains(thename)){
    mymap.put(thename, newSum);
}

这是你如何使用它的一个例子。这是一个帮助您入门的链接:http://java67.blogspot.gr/2013/02/10-examples-of-hashmap-in-java-programming-tutorial.html

答案 4 :(得分:0)

如果存在具有相同名称的元素,我建议甚至不对该列表执行.add()来优化(如果可能)。使用其中一个基于散列的集合与适当的equals()&amp;基于MyClass.name的hashCode()实现也应该会给你一些好的表现。

答案 5 :(得分:0)

首先,因为你不能覆盖equals或hashCode,所以你需要在与MyClass类相同的包中具有执行此功能的函数,因为MyClass

中没有定义访问器方法

其次,尝试将您的项目放在LinkedList中,以便您可以非常快速地从该列表中删除重复元素,而无需移动其他项目。

使用地图跟踪与给定名称对应的金额,同时迭代列表,同时删除重复元素。这样您就不必创建新列表。

List<MyClass> myClass_l;

Map<String, MyClass> nameMyClass_m = new HashMap<String, MyClass>();

for (Iterator<MyClass> iterator = myClass_l.iterator(); iterator.hasNext(){
    MyClass m = iterator.next();
    if (nameAmount_m.contains(m.name)){
        MyClass firstClass = m.get(m.name);
        firstClass.amount += m.amount;
        iterator.remove();
    }
    else{
        nameMyClass_m.put(m.name, m);
    }
}

当您完成循环时,您将在原始列表中包含所需的项目。