假设我有这个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 = ???;
在列表中
当然有简单的老迭代,但我认为应该有更优雅的东西(可能涉及流,但不是强制性的),但我不太明白...
我可以想到一些好的解决方案,包括覆盖
并使用equals()
方法以基本上返回id==other.id;Set
或()
。不幸的是,我不能覆盖equals()
,因为对象相等性不能改变。
实现这一目标的明确有效方法是什么?
你可以写这个。由于filter()
和使用Set来存储遇到的id,这将跳过具有相同id的第二个和下一个元素:
Set<Long> ids = new HashSet<>();
List<Foo> uniqueFoos = Stream.concat(getListA().stream(), getListB().stream())
.filter(f -> ids.add(f.getId()))
.collect(Collectors.toList());
这不是一个完整的流解决方案,但它是相当直接和可读性。
像这样的事情就可以了。
List<Foo> uniqueFoos = Stream.concat(listA.stream(), listB.stream())
.filter(distinctByKey(Foo::getId))
.collect(Collectors.toList());
public <T> Predicate<T> distinctByKey(Function<? super T, ?> keyExtractor) {
Set<Object> seen = ConcurrentHashMap.newKeySet();
return t -> seen.add(keyExtractor.apply(t));
}
您可以使用Collectors.toMap
:
Collection<Foo> uniqueFoos = Stream.concat(listA.stream(), listB.stream())
.collect(Collectors.toMap(
Foo::getId,
f -> f,
(oldFoo, newFoo) -> oldFoo))
.values();
如果您需要列表
而不是集合
,只需执行以下操作:
List<Foo> listUniqueFoos = new ArrayList<>(uniqueFoos);
如果还需要保留元素的相遇顺序,则可以使用<code>收集器的重载版本。toMap接受返回地图的供应商
:
Collection<Foo> uniqueFoos = Stream.concat(listA.stream(), listB.stream())
.collect(Collectors.toMap(
Foo::getId,
f -> f,
(oldFoo, newFoo) -> oldFoo,
LinkedHashMap::new))
.values();
我认为值得添加一个非流变量:
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();
这可以重构为通用方法以不重复代码:
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();
}
您可以按如下方式使用它:
Collection<Foo> uniqueFoos = uniqueBy(Foo::getId, listA, listB);
此方法使用 Map.merge
方法。
问题内容: 写一个方法 公共静态ArrayList merge(ArrayList a,ArrayList b) 合并两个数组列表,两个数组列表中的元素交替出现。如果一个数组列表短于另一个数组列表,则请尽可能长地交替,然后附加较长数组列表中的其余元素。例如,如果a是 1 4 9 16 b是 9 7 4 9 11 然后合并返回数组列表 1 9 4 7 9 4 16 9 11 我尝试做的是编写一个带i
我想在java中创建一个方法,该方法接收两个字符串列表:
我今天用Java编写了一个网关(我是一个初学者),允许接收一个包含以下信息的帧:ETQ | RGS | B | MESSAGE | ETX | CHECKSUM。我想解析帧以获得RGS和消息,我对这一部分进行了编码,但我想在同一个列表中添加这两个元素和属性。这可能吗? 这是我的代码: 非常感谢您的帮助
问题内容: 如果我有两个清单 什么是获取熊猫数据框的最优雅的方式,如下所示: 注意,第一列是索引。 问题答案: 使用于:
假设我有一个由n个字符串列表组成的列表: result->包含所有输出列表(所有组合) current->是当前的组合 用上述相同示例调用此函数时的输出:
问题内容: 在最近的一次采访中有人问我这个问题。 您将获得一个包含一百万个元素的数组。除了一个元素外,所有元素都是重复的。我的任务是找到独特的元素。 我的做法是要经过在整个数组循环,然后创建一个索引作为数组中和的数组中出现的次数。然后再次遍历我们的地图,并返回值为1的索引。 我说我的方法会花费时间。面试官告诉我要以低于复杂度的方式对其进行优化。我说过,我们不能,因为我们必须遍历具有一百万个元素的整