我认为没有绕过地图的方法。但是,你可以使用 groupingBy
来隐藏它,但这与 Paul Boddington 建议的代码和性能实际上是相同的。
List<A> merge(List<A> input) {
return input.stream()
.collect(groupingBy(a -> a.name)) // map created here
.entrySet()
.stream()
.map(entry -> new A(
entry.getKey(),
entry.getValue().stream()
.flatMap(list -> list.numbers.stream())
.collect(toList()) // merging behaviour
)).collect(toList());
}
原始列表没有变异,您可以轻松更改合并列表的行为 - 例如,如果要摆脱重复项,请在
flatMap(list -> list.numbers.stream())
之后添加
.distinct()
(记住将
equals
添加到
B
),或者以类似的方式通过添加
.sorted()
对它们进行排序(您必须使B实现
Comparable
接口或只使用
.sorted(Comparator<B>)
)。
这是完整的代码,包括测试和导入:
import org.junit.Test;
import java.util.List;
import static com.shazam.shazamcrest.MatcherAssert.assertThat;
import static com.shazam.shazamcrest.matcher.Matchers.sameBeanAs;
import static java.util.Arrays.asList;
import static java.util.stream.Collectors.groupingBy;
import static java.util.stream.Collectors.toList;
public class Main {
class A {
final String name;
final List<B> numbers;
A(String name, List<B> numbers) {
this.name = name;
this.numbers = numbers;
}
}
class B {
final Integer number;
B(Integer number) {
this.number = number;
}
}
List<A> merge(List<A> input) {
return input.stream()
.collect(groupingBy(a -> a.name))
.entrySet()
.stream()
.map(entry -> new A(
entry.getKey(),
entry.getValue().stream()
.flatMap(list -> list.numbers.stream())
.collect(toList())
)).collect(toList());
}
@Test
public void test() {
List<A> input = asList(
new A("abc", asList(new B(1), new B(2))),
new A("xyz", asList(new B(3), new B(4))),
new A("abc", asList(new B(3), new B(5)))
);
List<A> list = merge(input);
assertThat(list, sameBeanAs(asList(
new A("abc", asList(new B(1), new B(2), new B(3), new B(5))),
new A("xyz", asList(new B(3), new B(4)))
)));
}
}
编辑:
根据您在评论中的问题,如果您想将多个字段添加到groupingBy
子句中,则需要创建一个表示映射键的类。如果您有不想包含在键中的字段,则必须定义如何合并两个不同的值 - 类似于您在数字上所做的操作。根据字段是什么,合并行为可以只选择第一个值并丢弃其他值(就像我在下面的代码中对numbers
所做的那样)。
class A {
final String name;
final String type;
final List<B> numbers;
A(String name, String type, List<B> numbers) {
this.name = name;
this.type = type;
this.numbers = numbers;
}
}
class B {
final Integer number;
B(Integer number) {
this.number = number;
}
}
class Group {
final String name;
final String type;
Group(String name, String type) {
this.name = name;
this.type = type;
}
}
List<A> merge(List<A> input) {
return input.stream()
.collect(groupingBy(a -> new Group(a.name, a.type)))
.entrySet()
.stream()
.map(entry -> new A(
entry.getKey().name,
entry.getKey().type,
entry.getValue().get(0).numbers
)).collect(toList());
}
A
和B
是伪代码,但后来意识到它们是完整的可以编译的类。 - Paul Boddington