java 帮助程序 class 用于列表中的 merging/filling 个元素

java helper class for merging/filling elements in list

这是我们代码库中的常见模式,当将模型列表从(例如)Thing 映射到 MyModel 时:

List<MyModel> myModelList = new ArrayList<>();
for (Thing thing : things) {
    MyModel myModel = new MyModel(thing.getId());
    if (myModelList.contains(myModel)) {
        myModel = myModelList.get(myModelList.indexOf(myModel));
    } else {
        myModel.setName(thing.getName());
        myModelList.add(myModel);
    }
    myModel.setSomeQuantity(myModel.getSomeQuantity() + thing.getSomeQuantity());
}

(假设 MyModel 有 equals() 和 hashCode() 使用 id 来决定是否相等)

这可以通过一些不同的方式来完成,你可以使用一个以 id 作为键的映射等等。我们可以为它制作一个通用的助手 class,它可以在任何地方使用。

但我想知道的是,是否已经有一些助手 class 或其他类型的构造已经以一种有效和干净的方式,在某些 java、apache、spring、google 或其他库?

这听起来更像是 Set 的工作,而不是列表。

A collection that contains no duplicate elements. More formally, sets contain no pair of elements e1 and e2 such that e1.equals(e2), and at most one null element.

Set<MyModel> myModelSet = new HashSet<>();
for (Thing thing : things) {
    MyModel myModel = new MyModel(thing.getId());
    myModel.setName(thing.getName());
    // copy more fields if nessecary or write a copyFromThing() method  or a constructor that accepts Thing as a parameter in the MyModel class

    myModel.setSomeQuantity(myModel.getSomeQuantity() + thing.getSomeQuantity());
    myModelSet.add(myModel);
}

编辑:问题是,当 MyModel 有更多字段要复制时,Set 没有 get 方法,这将是一个问题

您在 List 上同时使用 containsindexOf。这两者通常都需要线性搜索,因此应尽可能避免。你绝对不应该像那样在 contains 之后直接使用 indexOf。你永远不需要这样做

if (list.contains(x)) 
    x = list.get(list.indexOf(x));

因为你总是可以这样做

int index = list.indexOf(x);
if (index >= 0)
    x = list.get(index);

这是更多代码,但避免了两次搜索列表。

但是,我不喜欢你使用 equalshashCode。通常, equal 对象可以互换处理,而在您的情况下, myModel 的两个版本并不相同;只有已经在列表中的那个带有关于名称和总量的额外信息。

我建议用只有两个字段(idname)的不可变 class MyModel 替换 MyModel。然后你可以这样做(假设你使用的是 Java 8)

Map<MyModel, Double> quantities = new HashMap<>();
for (Thing thing : things)
    quantities.merge(thing.getModel(), thing.getQuantity(), Double::sum);