我有两个Java对象列表
比方说dataToBeAdded,dataToBeSubtracted
这些对象具有相同的数据类型,并具有多个属性。
DummyObject{ attr1,attr2,attr3,attr4 }
我想合并这些列表,但是如果attr1、attr2、attr3在列表中匹配,则以有条件的方式进行合并
减去attr4并使其成为列表的一部分。
如果属性不匹配
这就像是一个完全的外连接操作
我用地图和溪流做了一些事情
Map<String, DummyObj> dataToBeAddedMap = dataToBeAdded.stream()
.collect(Collectors.toMap(obj -> obj.attr1() + obj.attr2() + obj.attr3(), item -> item));
Map<String, CumulativeSalesDataByHour> dataToBeSubtractedMap = dataToBeSubtracted.stream()
.collect(Collectors.toMap( obj -> obj.attr1() + obj.attr2() + obj.attr3(), item ->
new DummyObject(item.attr1(), item.attr2(), item.attr3(), -1 * item.attr4())));
Map<String, DummyObject> resultantData = Stream.of(dataToBeAddedMap, dataToBeSubtractedMap)
.flatMap(map -> map.entrySet().stream())
.collect(Collectors.toMap(
Map.Entry::getKey,
Map.Entry::getValue,
(v1, v2) -> new DummyObject(v1.attr1(),
v1.attr2(),
v1.attr3(),
v1.attr4() + v2.attr4())
));
System.out.println(resultantData.values());这给了我想要的结果,但是否有更有效的方法来实现这一点呢?
编辑1:
添加输入和预期输出
DummyObject a1 = new DummyObject("uuid1", "abcd", "mer1", 20D);
DummyObject a2 = new DummyObject("uuid1", "pqrs", "mer1", 25D);
DummyObject a3 = new DummyObject("uuid2", "xyz", "mer1", 18D);
List<DummyObject> dataToBeAdded = ImmutableList.of(a1,a2,a3);
DummyObject d1 = new DummyObject("uuid1", "abcd", "mer1", 5D);
DummyObject d2 = new DummyObject("uuid1", "pqrs", "mer1", 2D);
DummyObject d3 = new DummyObject("uuid3", "xyz", "mer2", 10D);
List<DummyObject> dataToBeSubtracted = ImmutableList.of(d1,d2,d3);
Desired Output
[
DummyObject("uuid1", "abcd", "mer1", 15D); // 20-5
DummyObject("uuid1", "pqrs", "mer1", 23D); // 25-2
DummyObject("uuid2", "xyz", "mer1", 18D);
DummyObject("uuid3", "xyz", "mer1", -10D);
] 发布于 2022-05-25 07:42:53
与其为要添加的元素和要减去的元素创建两个额外的Map,不如立即使用两个List创建一个链式流,并将减法List的每个元素映射到一个attr4字段已经被否定的元素。
然后,您可以使用Map终端操作在单个collect(Collectors.toMap())中收集所有对象。关键是前3个字段的连接,值将是对象本身,而冲突案例可以通过创建一个新的DummyObj来处理,该字段与您要分组的3个字段相同,第四个字段由第一个和第二个碰撞值的attr4之和(类似于您在上一个流中所做的)。
另一个小的改进可能不是将字符串与+操作符链接起来,后者为每个连接创建一个新的String,而是使用String.format()方法生成单个String来按(减少开销)对元素进行分组。
Map<String, DummyObj> mapRes = Stream.concat(dataToBeAdded.stream(), dataToBeSubtracted.stream().map(obj -> {
obj.setAttr4(-1 * obj.getAttr4());
return obj;
}))
.collect(Collectors.toMap(obj -> String.format("%s%s%s", obj.getAttr1(), obj.getAttr2(), obj.getAttr3()),
Function.identity(),
(obj1, obj2) -> new DummyObj(obj1.getAttr1(), obj1.getAttr2(), obj1.getAttr3(), obj1.getAttr4() + obj2.getAttr4())
));下面是测试上面代码的链接:
发布于 2022-05-25 08:32:54
如果你真的想要性能,你需要重写管道--无论发生什么事情,你都会问这个问题?使用前3个属性作为键(也许可以创建一个新的类来表示这3个属性),这样就有了两个映射。
但是,如果管道不能改变,最快的算法是:
iterator-1.
它将大大增加代码,但它不会产生任何新的瞬态对象,除了两个迭代器和一个比较器。
https://stackoverflow.com/questions/72373297
复制相似问题