【问题标题】:Filtering List of Maps in Java 8Java 8 中的地图过滤列表
【发布时间】:2021-07-01 09:53:55
【问题描述】:

我有一个地图数据结构列表。我需要通过在每个地图中搜索一个值来过滤列表(结果总是只有一个地图)。下面的代码显示了我执行此操作的两种方法。虽然我的 Lambda 方法有效,但对我来说似乎很臃肿。我觉得我在这里遗漏了一些简单的东西,并且有一个更简洁的 Lambda 可以用来代替这个。我将不胜感激任何使 Lambda 变得更好的建议。非常感谢。


package test;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

public class Temp {

  public static void main(String[] args) {

    Map<String, String> map1 = new HashMap<>();
    map1.put("map1-key1", "map1-value-1");
    map1.put("map1-key2", "map1-value-2");
    map1.put("map1-key3", "map1-value-3");
    
    Map<String, String> map2 = new HashMap<>();
    map2.put("map2-key1", "map2-value-1");
    map2.put("map2-key2", "some_wanted_value");
    map2.put("map2-key3", "map2-value-3");

    Map<String, String> map3 = new HashMap<>();
    map3.put("map3-key1", "map3-value-1");
    map3.put("map3-key2", "map3-value-2");
    map3.put("map3-key3", "map3-value-3");

    List<Map<String, String>> LOMs = new ArrayList<>();
    
    LOMs.add(map1);
    LOMs.add(map2);
    LOMs.add(map3);

    String column = "some_wanted_value";
      
    // Imperative method.  
    Map<String, String> x = new HashMap<>();
    for(Map<String, String> lom : LOMs) {
      if(lom.containsValue(column)) {
        x = lom;
        break;
      }
    }
    x.forEach((k,v) -> System.out.println(k + "->" + v));
    /*
    map2-key1->map2-value-1
    map2-key3->map2-value-3
    map2-key2->some_wanted_value
     */

    // Lambda method.
    Map<String, String> y = LOMs
      .stream()
      .filter(s -> s.containsValue(column))
      .flatMap(s -> s.entrySet().stream())
      .map(s -> s.toString().split("="))
      .collect(Collectors.toMap(s -> s[0], s -> s[1], (o, n) -> o));
    y.forEach((k,v) -> System.out.println(k + "->" + v));
    /*
    map2-key1->map2-value-1
    map2-key3->map2-value-3
    map2-key2->some_wanted_value
     */

  }
}

【问题讨论】:

    标签: java list java-stream maps


    【解决方案1】:

    它应该简单得多:

    Map<String, String> result = LOMs.stream()
        .filter(map -> map.containsValue(column))
        .findFirst() // returns Optional
        .get(); // use get if you're sure that you always have one result
    

    如果可能没有结果,请使用Optional#orElse(用于值)或Optional#orElseGet(用于功能接口)。

    您可以阅读有关可选的更多信息,例如,here

    【讨论】:

    • 不幸的是,使用get() 是一种反模式,请尝试orElse / orElseGetifPresent
    【解决方案2】:

    您只需将 sprint 的结果限制为单个结果以匹配您的命令式解决方案,无需通过再次收集使其过于复杂

    LOMs.stream()
            .filter(s -> s.containsValue(column))
            .findFirst()
            .orElseGet(Collections::emptyMap)
            .forEach((k, v) -> System.out.println(k + "->" + v));
    

    另一种方法是使用ifPresent 而不是orElseGet 以确保您不会不必要地实例化地图,这当然取决于您的需要

    LOMs.stream()
            .filter(s -> s.containsValue(column))
            .findFirst()
            .ifPresent(map -> map.forEach((k, v) -> System.out.println(k + "->" + v)));
    

    这将打印与您的命令式解决方案相同的结果以及另一个涉及流的结果

    map2-key1->map2-value-1
    map2-key3->map2-value-3
    map2-key2->some_wanted_value
    

    【讨论】:

    • 谢谢,亚辛。两者都是不错的选择,并且是对原始 Lambda 的重大改进。
    • 不客气@Jack 随时投票/接受答案以结束此问题并明确此答案对您有所帮助
    • 谢谢,亚辛。我投了赞成票。因为我的代表只有 11 分,所以记录了赞成票但没有显示。对此感到抱歉。
    • @Jack 没问题,即使有 11 分也可以正常接受答案,这已经有助于解决问题
    猜你喜欢
    • 1970-01-01
    • 2017-06-21
    • 1970-01-01
    • 2018-02-07
    • 2015-07-12
    • 1970-01-01
    • 2021-11-06
    • 2019-05-24
    • 2021-12-20
    相关资源
    最近更新 更多