是否可以仅使用 reduce 函数将 Java Stream<T> 缩减为新的 Stream<T>
Is it possible to reduce a Java Stream<T> to a new Stream<T> solely with the reduce function
我正在尝试通过删除基于特定属性的重复项并增加这些属性的值,将对象流减少为相同对象类型的新流。在下面的动物示例中,我将匹配 typeOfAnimal,然后繁殖并对新动物的年龄求和。所以列表:
[
{"typeOfAnimal": "dog", "breed": "Labrador", "age": 5},
{"typeOfAnimal": "dog", "breed": "Labrador", "age": 3},
{"typeOfAnimal": "dog", "breed": "Poodle", "age": 7},
{"typeOfAnimal": "cat", "breed": "Bengal", "age": 1}
]
结果应如下所示:
[
{"typeOfAnimal": "dog", "breed": "Labrador", "age": 8},
{"typeOfAnimal": "dog", "breed": "Poodle", "age": 7},
{"typeOfAnimal": "cat", "breed": "Bengal", "age": 1}
]
到目前为止,为了实现这个结果,我不得不使用 groupingBy 和 reducing 收集器,因为我无法将其写为单个 reducer 运算符。这是我的工作示例:
Stream<Animal> results = animals
.stream()
.collect(
groupingBy(Animal::getTypeOfAnimal,
groupingBy(Animal::getBreed,
reducing(
new Animal().withAge(0),
(a,c) -> new Animal()
.withTypeOfAnimal(c.getTypeOfAnimal())
.withBreed(c.getBreed())
.withAge(c.getAge() + a.getAge())))))
.values()
.stream()
.flatMap(a -> a.values().stream());
reduce 运算符是否允许这样做,或者我是否需要坚持使用当前示例?我偏爱单个 reducer 函数是因为我的实际代码具有更多级别,因此有更多 groupingBy 语句
那么,您现在每次都按一个 属性 分组。
但您也可以立即按所需属性分组:
首先,创建一条GroupingKey
记录:
public static record GroupingKey(String type, String breed) {
public static GroupingKey of(Animal animal) {
return new GroupingKey(animal.getTypeOfAnimal(), animal.getBreed());
}
}
这有助于我们定义动物在哪些领域进行分组。
然后我们定义一个merge
方法,它有助于合并两个动物。
private static Animal merge(Animal a, Animal b) {
int age = (a != null ? a.getAge() : 0);
return new Animal(b.getTypeOfAnimal(), b.getBreed(), age + b.getAge());
}
然后你可以减少一次:
Map<GroupingKey, Animal> map = animals.stream()
.collect(groupingBy(GroupingKey::of, reducing(null, t -> merge(t))));
然后通过调用 values()
,您可以检索包含所有 Animal
的 Collection
。
我正在尝试通过删除基于特定属性的重复项并增加这些属性的值,将对象流减少为相同对象类型的新流。在下面的动物示例中,我将匹配 typeOfAnimal,然后繁殖并对新动物的年龄求和。所以列表:
[
{"typeOfAnimal": "dog", "breed": "Labrador", "age": 5},
{"typeOfAnimal": "dog", "breed": "Labrador", "age": 3},
{"typeOfAnimal": "dog", "breed": "Poodle", "age": 7},
{"typeOfAnimal": "cat", "breed": "Bengal", "age": 1}
]
结果应如下所示:
[
{"typeOfAnimal": "dog", "breed": "Labrador", "age": 8},
{"typeOfAnimal": "dog", "breed": "Poodle", "age": 7},
{"typeOfAnimal": "cat", "breed": "Bengal", "age": 1}
]
到目前为止,为了实现这个结果,我不得不使用 groupingBy 和 reducing 收集器,因为我无法将其写为单个 reducer 运算符。这是我的工作示例:
Stream<Animal> results = animals
.stream()
.collect(
groupingBy(Animal::getTypeOfAnimal,
groupingBy(Animal::getBreed,
reducing(
new Animal().withAge(0),
(a,c) -> new Animal()
.withTypeOfAnimal(c.getTypeOfAnimal())
.withBreed(c.getBreed())
.withAge(c.getAge() + a.getAge())))))
.values()
.stream()
.flatMap(a -> a.values().stream());
reduce 运算符是否允许这样做,或者我是否需要坚持使用当前示例?我偏爱单个 reducer 函数是因为我的实际代码具有更多级别,因此有更多 groupingBy 语句
那么,您现在每次都按一个 属性 分组。
但您也可以立即按所需属性分组:
首先,创建一条GroupingKey
记录:
public static record GroupingKey(String type, String breed) {
public static GroupingKey of(Animal animal) {
return new GroupingKey(animal.getTypeOfAnimal(), animal.getBreed());
}
}
这有助于我们定义动物在哪些领域进行分组。
然后我们定义一个merge
方法,它有助于合并两个动物。
private static Animal merge(Animal a, Animal b) {
int age = (a != null ? a.getAge() : 0);
return new Animal(b.getTypeOfAnimal(), b.getBreed(), age + b.getAge());
}
然后你可以减少一次:
Map<GroupingKey, Animal> map = animals.stream()
.collect(groupingBy(GroupingKey::of, reducing(null, t -> merge(t))));
然后通过调用 values()
,您可以检索包含所有 Animal
的 Collection
。