【问题标题】:Java 8 double for loop to stream filter mapJava 8 double for 循环流过滤器映射
【发布时间】:2021-09-02 13:01:51
【问题描述】:

我的代码原样:

List<TestDto> dto = selectList();
List<TestDto2> dto2 = selectList2();
Map<String, Object> result = new HashMap<>();

for( TestDto d : dto )
{
  for( TestDto2 d2 : dto2 )
  {
    if( (d1.getHeight() == d2.getHeight()) && (d1.getAge() == d2.getAge()) ) 
    {
      result.put( d2.getName() + "_H", d1.getHeight() );
      result.put( d2.getName() + "_A", d1.getAge() );
    }
  }
}

成为:

    ?
/*
    example) dto.stream().filter(dto2.stream(d2... -> d1.getHeight = d2.getHeight && d1.getAge == d2.getAge).map....result.put()...
*/

我想要 Java 8 Stream 代码。

谁能帮帮我?

使用我想从 for 循环流式传输的 Java 8 流, 获取所有地图,所有过滤对象的列表。

【问题讨论】:

  • TestDtoTestDto2 实际上是两个不同的类吗?
  • 除非getHeight 是公共布尔字段,否则您的代码不会编译。

标签: java dictionary java-8 java-stream


【解决方案1】:

IMO,最好按照您已经完成的方式完成。但是,如果您仍然想使用Stream API,您可以通过以下方式进行:

dto.stream().forEach(d1 -> dto2.stream().forEach(d2 -> {
    if (d1.getHeight() == d2.getHeight() && d1.getAge() == d2.getAge()) {
        result.put(d2.getName() + "_H", d1.getHeight());
        result.put(d2.getName() + "_A", d1.getAge());
    }
}));

其实你不需要使用dto.stream()。你可以简单地使用ArrayList#forEach:

dto.forEach(d1 -> dto2.forEach(d2 -> {
    if (d1.getHeight() == d2.getHeight() && d1.getAge() == d2.getAge()) {
        result.put(d2.getName() + "_H", d1.getHeight());
        result.put(d2.getName() + "_A", d1.getAge());
    }
}));

【讨论】:

  • 如果你直接调用forEach(),那么你不需要调用stream()
【解决方案2】:

我会使用您现有的方法进行以下更改。

List<TestDto> dto = selectList();
List<TestDto2> dto2 = selectList2();
Map<String, Object> result = new HashMap<>();

outer:
for (TestDto2 d2 : dto2) {
    for (TestDto d1 : dto) {
        if ((d1.getHeight() == d2.getHeight())
                && (d1.getAge() == d2.getAge())) {
            result.put(d2.getName() + "_H", d1.getHeight());
            result.put(d2.getName() + "_A", d1.getAge());
            continue outer;
        }
    }
}

  • 颠倒循环的顺序,使外面的循环具有名称属性
  • 找到匹配项并在映射中输入条目后,继续外循环。

如果您打印此内容而不是放入地图,则上述内容将避免重复出现。由于地图忽略了重复的键,它仍然可以确保您在匹配后不会进行不必要的比较。

但是,如果您有两个同名但年龄和/或身高不同的人,您仍然会遇到问题。最新的将替换现有的。解决这个问题的一种方法是在名称上附加一个数字,然后增加数字。这将确保您可以拥有多个同名。

【讨论】:

    【解决方案3】:
    import org.apache.commons.lang3.tuple.Pair;
    
    Map<String, Object> result =
            dto.stream()
               .flatMap(d1 -> dto2.stream().map(d2 -> Pair.of(d1, d2)))
               .filter(pair -> pair.getLeft().getHeight() == pair.getRight().getHeight())
               .filter(pair -> pair.getLeft().getAge() == pair.getRight().getAge())
               .flatMap(pair -> Stream.of(
                       Pair.of(pair.getRight().getName() + "_H", pair.getLeft().getHeight()),
                       Pair.of(pair.getRight().getName() + "_A", pair.getLeft().getAge())))
               .collect(Collectors.toMap(Pair::getLeft, Pair::getRight));
    

    【讨论】:

      【解决方案4】:
      dto2.stream().filter(testDto2 -> dto.stream().
                      anyMatch(testDto ->
                              testDto2.getAge() == testDto.getAge() && testDto2.getHeight() == testDto.getHeight()))
                      .forEach(testDto2 ->
                              {
                                  result.put(testDto2.getName() + "_H", testDto2.getHeight());
                                  result.put(testDto2.getName() + "_A", testDto2.getAge());
      
                              }
                      );
      

      【讨论】:

      • 这不是一个好方法,因为 Stream API 会产生副作用。
      猜你喜欢
      • 1970-01-01
      • 2018-01-01
      • 2019-01-08
      • 2022-01-18
      • 2017-05-09
      • 2017-01-20
      • 2018-08-08
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多