我有两个类型Entity
的集合。
class Entity {
long id;
// other fields
}
Collection<Entity> first = ...
Collection<Entity> second = ...
我需要将它们组合在一起,first
中的所有元素都应该被second
中的元素替换,如果它们的ID相等。
所以,例如first
包含[{"id": 1}, {"id": 2}, {"id": 3}]
且second
包含[{"id": 3}, {"id": 4}, {"id": 5}]
结果应如下所示:[{"id": 1}, {"id": 2}, {"id": 3}, {"id": 4}, {"id": 5}]
{"id": 3}
second
从{"id": 3}
替换 <plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<version>2.10</version>
<executions>
<execution>
<id>unpack</id>
<phase>process-resources</phase>
<goals>
<goal>unpack</goal>
</goals>
<configuration>
<artifactItems>
<artifactItem>
<groupId>org.seleniumhq.selenium</groupId>
<artifactId>selenium-ie-driver</artifactId>
<version>3.0.1</version>
</artifactItem>
</artifactItems>
</configuration>
</execution>
</executions>
</plugin>
。
有没有办法如何使用Stream API以Java 8方式实现它。
答案 0 :(得分:2)
虽然可以使用一个流操作来执行整个操作,但由于对集合的重复迭代,结果将不是非常有效。强烈建议在这里使用两个操作
Map<Long,Entity> secondById = second.stream()
.collect(Collectors.toMap(Entity::getId, Function.identity()));
Collection<Entity> result = first.stream()
.map(e -> secondById.getOrDefault(e.getId(), e))
.collect(Collectors.toList());
请注意,我执行了您的任务说明“first
中的元素应该替换为second
中的元素,如果它们的ID相等”,例如它不会插入第二个没有匹配元素的元素。如果first
具有已定义的遭遇订单,则会保留该订单。
请注意,如果first
是一个可变列表,您可以就地替换这些元素:
List<Entity> first = ...
Collection<Entity> second = ...
Map<Long,Entity> secondById = second.stream()
.collect(Collectors.toMap(Entity::getId, Function.identity()));
first.replaceAll(e -> secondById.getOrDefault(e.getId(), e));
将其更改为不只是替换first
的元素,而是添加second
的所有元素并不是那么难:
Map<Long,Entity> secondById = second.stream()
.collect(Collectors.toMap(Entity::getId, Function.identity()));
Collection<Entity> result = Stream.concat(
first.stream().filter(e -> !secondById.containsKey(e.getId())),
second.stream()
).collect(Collectors.toList());
答案 1 :(得分:1)
也许一些老式的,简单的Collection
方法可以帮到你:
first.removeAll(second);
first.addAll(second);
请注意,您必须实施hashCode
和equals
才能将id
用作实体类中的参数。
修改强>
由于您无法更改equals
,因此您可以使用Collection.removeIf
复制removeAll
的效果:
second.forEach(entity2 -> first.removeIf(entity1 -> entity1.getId() == entity2.getId()));
first.addAll(second);
答案 2 :(得分:1)
color
的流式表示:
first.removeAll(second).addAll(second)
这假设Stream<Entity> result = Stream.concat(
first.stream().filter(entity -> !second.contains(entity)),
second.stream());
中的相等实体与second
的区别在于非id字段值,与相等无关。
答案 3 :(得分:0)
您可以使用Map.merge(..)选择较新的记录。在下面的示例中,它在功能上等同于Map.put(..),但允许您比较其他实体属性,例如创建时间戳或其他。
// Extract Entity::getId as a Map key, and keep the Entity object as value
Map<Long, Entity> result = first.stream()
.collect(Collectors.toMap(Entity::getId, Function.identity()));
// Merge second collection into the result map, overwriting existing records
second.forEach(entity -> result.merge(entity.getId(), entity, (oldVal, newVal) -> newVal));
// Print result
result.values().forEach(System.out::println);
如果您只想使用Stream API,那么您可以使用Stream.concat(...)将两个集合连接成一个Stream,然后编写一个自定义收集器
Map<Long, Entity> result2 = Stream.concat(first.stream(), second.stream())
.collect(LinkedHashMap::new, // the placeholder type
(map, entity) -> map.merge(entity.getId(), entity, (oldVal, newVal) -> newVal),
(map1, map2) -> {}); // parallel processing will reorder the concat stream so ignore