在java列表中合并类似对象的最佳方式是什么



这是我的问题(简化):

假设我们有一个类:

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

List<MyClass> myList

假设我们有myList中的2个元素。比方说object1object 2

我想做的是:

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

考虑到我有一个很大的列表(可能有100个元素),我想找到做我想做的事情的最佳且消耗较少的方式

你有什么建议?


编辑:

  • 是的,100个项目不是很大,但我会多次调用这种方法(合并类似对象)来处理许多不同大小的列表。所以这就是我想找到的最佳做法。

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

我会将对象添加到HashMap中,其中name是键,MyClass是要存储的值。循环浏览列表中的每个对象,将它们添加到地图中。如果名称不在地图中,只需添加名称、对象对即可。如果它已经在地图中,请将数量添加到已经存储的对象中。循环完成后,从地图中提取对象。

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

不幸的是,这是一个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);
}

"大"是相对的,100个项目肯定不算大,想象一下,如果你必须每秒处理1.000.000个项目。然后你会重新定义大:D

在您的示例中,我认为最好避免创建一组项目名称。搜索java哈希集需要O(1),因此如果哈希集中存在对象的名称,则在列表中更新它。一个更好的解决方案是创建一个HashMap,你可以在上面说,例如

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

这是一个如何使用它的例子。下面是一个让你开始使用的链接:http://java67.blogspot.gr/2013/02/10-examples-of-hashmap-in-java-programming-tutorial.html

如果存在同名元素,我建议(如果可能的话)甚至不对列表执行.add()来进行优化。将基于哈希的集合之一与适当的equals()&基于MyClass.name的hashCode()实现也会给您带来一些不错的性能。

首先,由于您不能重写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);
    }
}

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

相关内容

  • 没有找到相关文章

最新更新