Java 按对象对地图进行分组';将属性添加到新映射

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

首先,让我添加实际的“示例代码”:

我还得到了“非静态不能被引用错误”(Map.Entry::getKey),但这是由于我未能匹配实际的预期返回()

在这一点上我很困惑,我也尝试过使用
收集器.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的答案后,我感到困惑。。。以一种好的方式。两者都提供了期望的结果(也用“糟糕”的解决方案更新了问题),这是按照我想要的方式构建的。我现在正在和自己讨论
收集器
分组方式
嵌套。。。你对这个和另一个答案有什么看法?我现在真的有分歧了。问题的解决办法是这样的