将地图值转换为另一个地图对象

tom*_*tom 1 java hashmap java-stream

我有一张这样的地图。Map<long,List<Student>> studentMap

键是数字 1,2,3,4...学生对象是:

public class Student {
 private long addressNo;
 private String code;
 private BigDecimal tax;
 private String name;
 private String city;

 // getter and setters` 
}
Run Code Online (Sandbox Code Playgroud)

我想要做的是将其转换为Map<long,List<StudentInfo>> studentInfoMap对象和组 ID、地址号和代码字段。

我可以使用这些代码对地图进行分组,但 summingDouble 不适用于 BigDecimal。此外,我无法将我的 StudentMap 转换为 StudentInfoMap。:(

 studentInfoMap.values().stream()
            .collect(
                     Collectors.groupingBy(StudentInfo::getCode, 
                     Collectors.groupingBy(StudentInfo::getAddressNo, 
                     Collectors.summingDouble(StudentInfo::getTax))));
Run Code Online (Sandbox Code Playgroud)

我的 StudentInfo 对象是:

public class StudentInfo {
  private long addressNo;
  private String code;
  private BigDecimal tax;

  // getter and setters` 
}
Run Code Online (Sandbox Code Playgroud)

Tho*_*mas 6

转换Map<K, List<A>>Map<K, List<B>> 如果您想将 a 转换Map<Long,List<Student>>为 a Map<Long,List<StudentInfo>>,并且键相同,请尝试以下操作:

Map<Long,List<StudentInfo>> convertedMap = 
  studentInfoMap.entrySet() //get the entry set to access keys and values
    .stream() 
    .collect(Collectors.toMap( //collect the entries into another map
        entry -> entry.getKey(), //use the keys as they are
        entry -> entry.getValue() //get the value list
                      .stream() /
                      .map(student -> new StudentInfo(/*pass in the student parameters you need*/) //create a StudentInfo out of a Student - and entry.getKey() if needed
                      .toList() //collect the StudentInfo elements into a list
     ));
Run Code Online (Sandbox Code Playgroud)

根据键值对 A 进行分组List<A>来简化List<B>

创建一个关键类

如果您想通过将和的每个独特组合的税费组合起来将a 折叠/减少List<Student>为 a ,那么理想情况下,您首先需要定义一个类,将这两个属性组合成一个键,例如List<StudentInfo>addressNocode

class StudentAddressKey {
  private long addressNo;
  private String code;

  //getters, setters, equals() and hashCode()
}
Run Code Online (Sandbox Code Playgroud)

然后您可以考虑使用它来Student代替单个键,但这是另一个主题。

传统循环

然后归结为通过这个键求和税收值。使用传统的 for 循环,它可能看起来像这样:

Map<StudentAddressKey, BigDecimal> taxByKey = new HashMap<>();

for( Student student : studentList) {
  taxByKey.merge(student.getAddressKey(), //or build a new one from the individual attributes
                 student.getTax(), //the value to merge into the map
                 BigDecimal::add ); //called if there's already a value in the map, could also be (e,n) -> e.add(n)
}
Run Code Online (Sandbox Code Playgroud)

如果您想要Map<StudentAddressKey, StudentInfo>替代,您有 3 个选择:

  • Student为您想要添加的每一个创建一个,将其传递给merge(),如果已经有一个,则将新的和现有的合并起来
  • 用于get()获取StudentInfo地图中已有的位置(如果已有)。如果您null换了新的,否则只需通过添加学生的价值来更改税费
  • 创建并最终Map<StudentAddressKey, BigDecimal>将其变成 a ,基本上使用我上面描述的过程。Map<StudentAddressKey, StudentInfo>

要获得 a List<StudentInfo>(如果您已经有 a ,则可能没有必要Map<StudentAddressKey, BigDecimal>),您再次有几个选择:

  • 如果您有一个Map<StudentAddressKey, BigDecimal>流条目集,请将每个条目映射到一个StudentInfo并收集到一个列表。
  • 如果您有一个 Map<StudentAddressKey, StudentInfo> just create a new list and pass the map'svalue()` 到列表构造函数

溪流

使用上面的信息,您还可以使用流来转换List<Student>List<StudentInfo>

Map<StudentAddressKey, BigDecimal> taxesMap = studentList.stream()
  .collect( 
     Collectors.groupingBy( student -> new StudentAddressKey(student), //create the key to group by
        Collectors.mapping( student -> student.getTax()), //map the student to its tax value
          Collectors.reducing( BigDecimal.ZERO, BigDecimal::add) //reduce the mapped tax values by adding them, starting with 0 (otherwise you'd get an Optional<BigDecimal>
        )
      )
    );
Run Code Online (Sandbox Code Playgroud)

注意:您也可以直接映射StudentStudentInfo,但合并它们会更复杂,因为您需要的只是一个,所以BigDecimal我会选择更简单的选项。

现在使用上面的方法转换taxesMapList<StudentInfo>

List<StudentInto> taxesList = taxesMap.entrySet().stream()
                .map( entry -> new StudentInfo(entry.getKey(), entry.getValue)) //map the entry to StudentInfo, provide the necessary constructor or adapt as needed
                .toList();
Run Code Online (Sandbox Code Playgroud)