假设我有这个Java 8代码:
public class Foo {
private long id;
public getId() {
return id;
}
//--snip--
}
//Somewhere else...
List<Foo> listA = getListA();
List<Foo> listB = getListB();
List<Foo> uniqueFoos = ???;
Run Code Online (Sandbox Code Playgroud)
在List<Foo> uniqueFoos我要添加的所有元素listA,并listB因此所有FooS ^具有唯一的ID.也就是说,如果已经有一个Foo在uniqueFoos具有特定ID不添加其他Foo具有相同ID但跳过它来代替.
当然有简单的旧迭代,但我认为应该有更优雅的东西(可能涉及流,但不是强制性的),但我无法弄清楚...
我可以想到一个好的解决方案,涉及equals()基本上覆盖方法return id == other.id;并使用Set或distinct().不幸的是我无法覆盖,equals()因为对象相等不能改变.
实现这一目标的清晰有效方法是什么?
你可以这样做Collectors.toMap:
Collection<Foo> uniqueFoos = Stream.concat(listA.stream(), listB.stream())
.collect(Collectors.toMap(
Foo::getId,
f -> f,
(oldFoo, newFoo) -> oldFoo))
.values();
Run Code Online (Sandbox Code Playgroud)
如果您需要List而不是a Collection,只需执行以下操作:
List<Foo> listUniqueFoos = new ArrayList<>(uniqueFoos);
Run Code Online (Sandbox Code Playgroud)
如果您还需要保留元素的遭遇顺序,则可以使用为Collectors.toMap接收到Supplier的映射接受a 的重载版本:
Collection<Foo> uniqueFoos = Stream.concat(listA.stream(), listB.stream())
.collect(Collectors.toMap(
Foo::getId,
f -> f,
(oldFoo, newFoo) -> oldFoo,
LinkedHashMap::new))
.values();
Run Code Online (Sandbox Code Playgroud)
我认为值得添加一个非流变体:
Map<Long, Foo> map = new LinkedHashMap<>();
listA.forEach(f -> map.merge(g.getId(), f, (oldFoo, newFoo) -> oldFoo));
listB.forEach(f -> map.merge(g.getId(), f, (oldFoo, newFoo) -> oldFoo));
Collection<Foo> uniqueFoos = map.values();
Run Code Online (Sandbox Code Playgroud)
这可以重构为通用方法,不重复代码:
static <T, K> Collection<T> uniqueBy(Function<T, K> groupBy, List<T>... lists) {
Map<K, T> map = new LinkedHashMap<>();
for (List<T> l : lists) {
l.forEach(e -> map.merge(groupBy.apply(e), e, (o, n) -> o));
}
return map.values();
}
Run Code Online (Sandbox Code Playgroud)
你可以使用如下:
Collection<Foo> uniqueFoos = uniqueBy(Foo::getId, listA, listB);
Run Code Online (Sandbox Code Playgroud)
这种方法使用该Map.merge方法.