[英]How to map multiple objects having two identical values and one different value to one object with list of those different values?
I have an object called RawCarEnumData
having 3 enums:我有一个名为 RawCarEnumData 的RawCarEnumData
有 3 个枚举:
public class RawCarEnumData {
private BrandEnum brand;
private ModelEnum model;
private ColorEnum color;
//getters, setters, constructors
}
and an object CarEnumData
having 2 enums and a list of enums:和一个 object CarEnumData
有 2 个枚举和一个枚举列表:
public class CarEnumData {
private BrandEnum brand;
private ModelEnum model;
private List<ColorEnum> colors;
//getters, setters, constructors
}
Now I have a list of RawCarEnumData
objects:现在我有一个RawCarEnumData
对象列表:
List<RawCarEnumData> rawCarEnumDataList = List.of(
new RawCarEnumData(BrandEnum.FORD, ModelEnum.FIESTA, ColorEnum.RED),
new RawCarEnumData(BrandEnum.FORD, ModelEnum.FIESTA, ColorEnum.BLUE),
new RawCarEnumData(BrandEnum.FORD, ModelEnum.FIESTA, ColorEnum.YELLOW),
new RawCarEnumData(BrandEnum.FORD, ModelEnum.FOCUS, ColorEnum.YELLOW)
}
Now I want to use stream API to map the List<RawCarEnumData>
to List<CarEnumData>
so the final output will look like this: Now I want to use stream API to map the List<RawCarEnumData>
to List<CarEnumData>
so the final output will look like this:
List<CarEnumData> carEnumData:
- CarEnumData(BrandEnum.FORD, ModelEnum.FIESTA, List.of(ColorEnum.RED, ColorEnum.BLUE, ColorEnum.YELLOW))
- CarEnumData(BrandEnum.FORD, ModelEnum.FOCUS, List.of(ColorEnum.YELLOW))
I have tried a few things but without success.我尝试了几件事,但没有成功。 How can this be achieved?如何做到这一点? Is this even possible?这甚至可能吗?
I know this is a Java question but I like to provide a Kotlin answer.我知道这是一个 Java 问题,但我想提供一个 Kotlin 答案。 It might help you come up with a Java solution or you might even want to include the Kotlin solution in your project since it should be interoperable with Java.它可能会帮助您提出 Java 解决方案,或者您甚至可能希望在您的项目中包含 Kotlin 解决方案,因为它应该与 Java 互操作。 The following code seems to do what you would like:以下代码似乎可以满足您的需求:
fun main() {
val rawCarEnumDataList = listOf(
RawCarEnumData(BrandEnum.FORD, ModelEnum.FIESTA, ColorEnum.RED),
RawCarEnumData(BrandEnum.FORD, ModelEnum.FIESTA, ColorEnum.BLUE),
RawCarEnumData(BrandEnum.FORD, ModelEnum.FIESTA, ColorEnum.YELLOW),
RawCarEnumData(BrandEnum.FORD, ModelEnum.FOCUS, ColorEnum.YELLOW)
)
val carEnumData = rawCarEnumDataList
.groupBy { Pair(it.brand, it.model) }
.values.map { cars -> CarEnumData(cars.first().brand,cars.first().model, cars.map { it.color }.distinct()) }
print(carEnumData)
// prints [CarEnumData(brand=FORD, model=FIESTA, colors=[RED, BLUE, YELLOW]), CarEnumData(brand=FORD, model=FOCUS, colors=[YELLOW])]
}
data class RawCarEnumData(
val brand: BrandEnum,
val model: ModelEnum,
val color: ColorEnum
)
data class CarEnumData (
val brand: BrandEnum,
val model: ModelEnum,
val colors: List<ColorEnum>
)
enum class BrandEnum { FORD }
enum class ModelEnum { FIESTA, FOCUS }
enum class ColorEnum { RED, BLUE, YELLOW }
So what you want to do is to group your RawCarEnumData
s by brand and model, and then reduce each list of RawCarEnumData
s into one CarEnumData
.因此,您要做的是将RawCarEnumData按品牌和 model 分组,然后CarEnumData
RawCarEnumData
的每个列表减少为一个RawCarEnumData
。 One way to do this would be the following:一种方法如下:
final var result =
rawCarEnumDataList.stream()
.collect(
Collectors.groupingBy(
car -> Map.entry(car.brand, car.model),
Collectors.mapping(
car -> new CarEnumData(car.brand(), car.model(), List.of(car.color)),
Collectors.collectingAndThen(
Collectors.reducing(
(car1, car2) ->
new CarEnumData(
car1.brand(),
car2.model(),
Stream.concat(car1.colors.stream(), car2.colors.stream())
.toList())),
Optional::orElseThrow))))
.values();
Breaking it down, the Collectors.groupingBy
gives you a map with keys given by applying a function, and a list of all values that corresponds to that key.分解它, Collectors.groupingBy
为您提供 map,其中键是通过应用 function 给出的,以及与该键对应的所有值的列表。 The second argument to Collectors.groupingBy
is a downstream collector of that list. Collectors.groupingBy
的第二个参数是该列表的下游收集器。 Here mapping
maps each value to a CarEnumData
with just a single color.此处的mapping
将每个值映射到仅具有一种颜色的CarEnumData
。 Collectors.mappingBy
also takes a downstream collector as a second argument, where I used Collectors.reducing
to merge all CarEnumData
s with the same brand and model into one, by merging the lists of colors with Stream.concat(car1.colors.stream(), car2.colors.stream()).toList()
. Collectors.mappingBy
also takes a downstream collector as a second argument, where I used Collectors.reducing
to merge all CarEnumData
s with the same brand and model into one, by merging the lists of colors with Stream.concat(car1.colors.stream(), car2.colors.stream()).toList()
。 The reducing collector returns an optional which is empty if there are no values in the stream, but in this case groupingBy
guarantees me at least one value in every group, so I can safely retrieve the value with Optional.orElseThrow()
.如果 stream 中没有值,则减少收集器返回一个为空的可选值,但在这种情况下, groupingBy
保证每个组中至少有一个值,因此我可以使用Optional.orElseThrow()
安全地检索该值。 Finally I can pick out the values()
of the map which is the desired collection.最后,我可以挑选出所需的集合 map 的values()
。
You didn't mention which Java version you use, if using an older version you may have to use collect(Collectors.toList)
and some other way to create the group key.您没有提到您使用哪个 Java 版本,如果使用旧版本,您可能必须使用collect(Collectors.toList)
和其他一些方式来创建组密钥。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.