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
上同时使用 contains
和 indexOf
。这两者通常都需要线性搜索,因此应尽可能避免。你绝对不应该像那样在 contains
之后直接使用 indexOf
。你永远不需要这样做
if (list.contains(x))
x = list.get(list.indexOf(x));
因为你总是可以这样做
int index = list.indexOf(x);
if (index >= 0)
x = list.get(index);
这是更多代码,但避免了两次搜索列表。
但是,我不喜欢你使用 equals
和 hashCode
。通常, equal
对象可以互换处理,而在您的情况下, myModel
的两个版本并不相同;只有已经在列表中的那个带有关于名称和总量的额外信息。
我建议用只有两个字段(id
和 name
)的不可变 class MyModel
替换 MyModel
。然后你可以这样做(假设你使用的是 Java 8)
Map<MyModel, Double> quantities = new HashMap<>();
for (Thing thing : things)
quantities.merge(thing.getModel(), thing.getQuantity(), Double::sum);
这是我们代码库中的常见模式,当将模型列表从(例如)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
上同时使用 contains
和 indexOf
。这两者通常都需要线性搜索,因此应尽可能避免。你绝对不应该像那样在 contains
之后直接使用 indexOf
。你永远不需要这样做
if (list.contains(x))
x = list.get(list.indexOf(x));
因为你总是可以这样做
int index = list.indexOf(x);
if (index >= 0)
x = list.get(index);
这是更多代码,但避免了两次搜索列表。
但是,我不喜欢你使用 equals
和 hashCode
。通常, equal
对象可以互换处理,而在您的情况下, myModel
的两个版本并不相同;只有已经在列表中的那个带有关于名称和总量的额外信息。
我建议用只有两个字段(id
和 name
)的不可变 class MyModel
替换 MyModel
。然后你可以这样做(假设你使用的是 Java 8)
Map<MyModel, Double> quantities = new HashMap<>();
for (Thing thing : things)
quantities.merge(thing.getModel(), thing.getQuantity(), Double::sum);