Java 按对象对地图进行分组';将属性添加到新映射
首先,让我添加实际的“示例代码”: 我还得到了“非静态不能被引用错误”(Map.Entry::getKey),但这是由于我未能匹配实际的预期返回() 在这一点上我很困惑,我也尝试过使用Java 按对象对地图进行分组';将属性添加到新映射,java,java-8,java-stream,method-reference,collect,Java,Java 8,Java Stream,Method Reference,Collect,首先,让我添加实际的“示例代码”: 我还得到了“非静态不能被引用错误”(Map.Entry::getKey),但这是由于我未能匹配实际的预期返回() 在这一点上我很困惑,我也尝试过使用收集器.toMap,但仍然无法获得有效的分组 附加服务 map.forEach((carType, brandMap) -> { System.out.println(carType); brandMap.forEach((brand, carList) -> { Sys
收集器.toMap
,但仍然无法获得有效的分组
附加服务
map.forEach((carType, brandMap) -> {
System.out.println(carType);
brandMap.forEach((brand, carList) -> {
System.out.println(" " + brand + " -> " + carList);
});
});
FAST
AUDI -> [{FAST, S3, yellow}, {FAST, R8, silver}]
BMW -> [{FAST, Z4, silver}, {FAST, M3, red}]
SLOW
AUDI -> [{SLOW, A1, white}]
BMW -> [{SLOW, X1, black}]
以下是此示例的类定义:
class CarBrand {
CarBrand(String name) {
this.name = name;
}
String name;
}
class Car {
Car(CarType type, String name, String color, String brandName) {
this.type = type;
this.name = name;
this.color = color;
this.brandName = brandName;
}
public CarType getType() {
return type;
}
CarType type;
String name;
String color;
String brandName;
}
enum CarType {
FAST,
SLOW,
}
编辑:“脏”解决方案
这里有一个“黑客”解决方案(根据评论和建议,我们将检查答案!):
Map mappedCars=allCarsAndBrands
.values()
.stream()
.flatMap(列表::流)
.collect(收集器.groupingBy(
汽车::getType,
收集者分组(
car->allCarsAndBrands.keySet().stream().filter(brand->brand.name==car.brandName.findFirst().get(),
收集者
)
));
正如评论中提到的(之前应该在这里添加),有一个“业务约束”为解决方案添加了一些限制。我也不想创建一个新的
CarBrand
,因为在现实世界中,这并不像本文中看到的那么简单。。。但同样,使用原始地图和过滤+查找是不好的。正如评论中所讨论的,如果将Make
作为Car
类的字段,那么这很简单
根据您上次的评论,最简单的方法是使用混合解决方案,使用Java 8中引入的Stream
和Map
接口的其他功能
数据
Map<CarBrand, List<Car>> allCarsAndBrands = new HashMap<>();
final String bmwBrandName = "BMW";
final String audiBrandName = "AUDI";
List<Car> bmwCars = new ArrayList<>();
bmwCars.add(new Car(CarType.FAST, "Z4", "silver"));
bmwCars.add(new Car(CarType.FAST, "M3", "red"));
bmwCars.add(new Car(CarType.SLOW, "X1", "black"));
List<Car> audiCars = new ArrayList<>();
audiCars.add(new Car(CarType.FAST, "S3", "yellow"));
audiCars.add(new Car(CarType.FAST, "R8", "silver"));
audiCars.add(new Car(CarType.SLOW, "A1", "white"));
allCarsAndBrands.put(new CarBrand(bmwBrandName), bmwCars);
allCarsAndBrands.put(new CarBrand(audiBrandName), audiCars);
打印结果
map.forEach((carType, brandMap) -> {
System.out.println(carType);
brandMap.forEach((brand, carList) -> {
System.out.println(" " + brand + " -> " + carList);
});
});
FAST
AUDI -> [{FAST, S3, yellow}, {FAST, R8, silver}]
BMW -> [{FAST, Z4, silver}, {FAST, M3, red}]
SLOW
AUDI -> [{SLOW, A1, white}]
BMW -> [{SLOW, X1, black}]
打印
map.forEach((carType, brandMap) -> {
System.out.println(carType);
brandMap.forEach((brand, carList) -> {
System.out.println(" " + brand + " -> " + carList);
});
});
FAST
AUDI -> [{FAST, S3, yellow}, {FAST, R8, silver}]
BMW -> [{FAST, Z4, silver}, {FAST, M3, red}]
SLOW
AUDI -> [{SLOW, A1, white}]
BMW -> [{SLOW, X1, black}]
注意:
{}
之间的值是toString
对Car
类的覆盖。如注释中所述,如果将Make
作为Car
类的一个字段,这是很简单的
根据您上次的评论,最简单的方法是使用混合解决方案,使用Java 8中引入的Stream
和Map
接口的其他功能
数据
Map<CarBrand, List<Car>> allCarsAndBrands = new HashMap<>();
final String bmwBrandName = "BMW";
final String audiBrandName = "AUDI";
List<Car> bmwCars = new ArrayList<>();
bmwCars.add(new Car(CarType.FAST, "Z4", "silver"));
bmwCars.add(new Car(CarType.FAST, "M3", "red"));
bmwCars.add(new Car(CarType.SLOW, "X1", "black"));
List<Car> audiCars = new ArrayList<>();
audiCars.add(new Car(CarType.FAST, "S3", "yellow"));
audiCars.add(new Car(CarType.FAST, "R8", "silver"));
audiCars.add(new Car(CarType.SLOW, "A1", "white"));
allCarsAndBrands.put(new CarBrand(bmwBrandName), bmwCars);
allCarsAndBrands.put(new CarBrand(audiBrandName), audiCars);
打印结果
map.forEach((carType, brandMap) -> {
System.out.println(carType);
brandMap.forEach((brand, carList) -> {
System.out.println(" " + brand + " -> " + carList);
});
});
FAST
AUDI -> [{FAST, S3, yellow}, {FAST, R8, silver}]
BMW -> [{FAST, Z4, silver}, {FAST, M3, red}]
SLOW
AUDI -> [{SLOW, A1, white}]
BMW -> [{SLOW, X1, black}]
打印
map.forEach((carType, brandMap) -> {
System.out.println(carType);
brandMap.forEach((brand, carList) -> {
System.out.println(" " + brand + " -> " + carList);
});
});
FAST
AUDI -> [{FAST, S3, yellow}, {FAST, R8, silver}]
BMW -> [{FAST, Z4, silver}, {FAST, M3, red}]
SLOW
AUDI -> [{SLOW, A1, white}]
BMW -> [{SLOW, X1, black}]
注意:
{}
之间的值是toString
对Car
类的覆盖。使用现有模型,以及您认为方向正确的嵌套分组的初始方法。在迭代条目时,可以考虑将Map
的值部分展平
allCarsAndBrands.entrySet().stream()
.flatMap(e -> e.getValue().stream()
.map(car -> new AbstractMap.SimpleEntry<>(e.getKey(), car)))
通过使用现有模型和嵌套分组的初始方法,您的思路是正确的。在迭代条目时,可以考虑将
Map
的值部分展平
allCarsAndBrands.entrySet().stream()
.flatMap(e -> e.getValue().stream()
.map(car -> new AbstractMap.SimpleEntry<>(e.getKey(), car)))
汽车
知道它的“型号”,但不知道它的“品牌”?你应该先解决这个问题。既然你在Car
对象中有了brand,就很容易了:allCarsAndBrands.values().stream().flatMap(List::stream().collector(Collectors.groupingBy(Car::getType,Collectors.groupingBy(Car::getBrand,Collectors.toList()))
我不明白:你想要所有的快车和慢车,不关心品牌,不是吗?Stream.concat(bmwCars,audiCars).collect(groupingBy(Car::getCarType))
足够了吗?当然,如果您不想把它放在Car
它所属的位置,请创建一个地图并查找它。我看不出有什么问题。汽车
知道它的“型号”,但不知道它的“品牌”?你应该先解决这个问题。既然你在Car
对象中有了brand,就很容易了:allCarsAndBrands.values().stream().flatMap(List::stream().collector(Collectors.groupingBy(Car::getType,Collectors.groupingBy(Car::getBrand,Collectors.toList()))
我不明白:你想要所有的快车和慢车,不关心品牌,不是吗?Stream.concat(bmwCars,audiCars).collect(groupingBy(Car::getCarType))
足够了吗?当然,如果您不想把它放在Car
它所属的位置,请创建一个地图并查找它。我看不出有什么问题。您好,非常感谢您在这方面花时间!我现在正在测试答案,到目前为止,我真的很喜欢这个。我的一位朋友也建议在最初的“工作”中使用foreach
,因为这会使事情更容易看,并便于最终的维护,但我一直在尝试不使用它。。。我将检查computeIfAbsent
文档,因为在尝试实现解决方案时完全跳过了此操作。我还更新了问题的“肮脏”解决方案,看一看(笑一笑)。您好,非常感谢您在这方面的时间!我现在正在测试答案,到目前为止,我真的很喜欢这个。我的一位朋友也建议在最初的“工作”中使用foreach
,因为这会使事情更容易看,并便于最终的维护,但我一直在尝试不使用它。。。我将检查computeIfAbsent
文档,因为在尝试实现解决方案时完全跳过了此操作。我还用“肮脏”的解决方案更新了这个问题,看一看(笑一笑)。嘿!谢谢你在这方面花时间。我还在检查两个答案。。。猜猜我也很喜欢这个!我的目标是这样的(没有/foreach的),但看到WJS的答案后,我感到困惑。。。以一种好的方式。两者都提供了期望的结果(也用“糟糕”的解决方案更新了问题),这是按照我想要的方式构建的。我现在正在和自己讨论收集器
和分组方式
嵌套。。。你对这个和另一个答案有什么看法?我现在真的有分歧了。问题的解决办法是这样的