Java流将EnumMap的映射转换为列表的映射

Java流将EnumMap的映射转换为列表的映射,java,collections,lambda,java-8,java-stream,Java,Collections,Lambda,Java 8,Java Stream,我希望将以下内容转换为 enum Parameter {Foo, Bar, Baz}; Map<String, EnumMap<Parameter, String>> myMap = new HashMap(){{ put("KEY1", new EnumMap<>(Parameter.class) {{ put(Parameter.Foo, "BAD"); put(Parameter.Bar, "GOOD"); p

我希望将以下内容转换为

enum Parameter {Foo, Bar, Baz};

Map<String, EnumMap<Parameter, String>> myMap = new HashMap(){{
   put("KEY1", new EnumMap<>(Parameter.class) {{
      put(Parameter.Foo, "BAD");
      put(Parameter.Bar, "GOOD");
      put(Parameter.Baz, "BAD");
   }});
   put("KEY2", new EnumMap<>(Parameter.class) {{
      put(Parameter.Foo, "BAD");
      put(Parameter.Bar, "GOOD");
      put(Parameter.Baz, "GOOD");
   }});
}};
enum参数{Foo,Bar,Baz};
Map myMap=newhashmap(){{
put(“KEY1”,新枚举映射(Parameter.class){{
put(Parameter.Foo,“BAD”);
put(Parameter.Bar,“GOOD”);
put(Parameter.Baz,“BAD”);
}});
put(“键2”,新枚举映射(Parameter.class){{
put(Parameter.Foo,“BAD”);
put(Parameter.Bar,“GOOD”);
put(Parameter.Baz,“GOOD”);
}});
}};
进入筛选映射,其中筛选将只包含

Map<String, List<Entry<Parameter, String>>> mapList
地图映射列表
其中,结果列表应包含以“良好”作为筛选条件的行

我无法找出正确的流语法来执行此操作,我知道其大致如下:

Map<String, List<Entry<Parameter, String>>> mapList =
    myMap.entrySet().stream().groupingBy(e -> e.getKey()).collect(Collectors.toMap(????)
地图映射列表=
myMap.entrySet().stream().groupingBy(e->e.getKey()).collect(Collectors.toMap(??)

条目已正确分组,只需将值展开并过滤:

import static java.util.stream.Collectors.*;
...
Map<String, List<Entry<Parameter, String>>> mapList = new HashMap<>();

myMap.forEach((k, v) -> { 
   List<Entry<Parameter, String>> filtered = v.entrySet().stream()
   .filter(e -> e.getValue().equals("GOOD"))
   .collect(toList());

   if(!filtered.isEmpty()) mapList.put(k, filtered);
});
导入静态java.util.stream.collector.*;
...
Map mapList=新建HashMap();
myMap.forEach((k,v)->{
列表筛选=v.entrySet().stream()
.filter(e->e.getValue().equals(“GOOD”))
.collect(toList());
如果(!filtered.isEmpty())mapList.put(k,filtered);
});

不清楚为什么要强调值的
EnumMap
性质,因为在使用特定的
Map
类型时,逻辑不会改变。您有一个要转换其值的映射,保留键,这意味着通过
收集器对条目进行流式处理和收集。toMap
是一种方法,让key函数返回原始键,value函数进行实际转换

这些值恰好是一个
映射
,您希望将其转换为
列表
,这非常简单,通过流式传输条目并将其收集到
列表
。添加一个过滤器以仅接受
“GOOD”
值非常简单

现在,遗憾的是,您没有在问题中指定它。如果目标映射中根本没有
“GOOD”
值,您希望省去外部映射的键。因此,您需要为外部流操作提供一个过滤器,这并不难,如果您还记得收集API有多强大,即使没有流:

Map<String, List<Map.Entry<Parameter, String>>> mapList
    = myMap.entrySet().stream()
        .filter(e -> e.getValue().containsValue("GOOD")) // need at least one GOOD there
        .collect(Collectors.toMap(
            Map.Entry::getKey, // keep original keys
            e -> e.getValue().entrySet().stream() // actual conversion
                .filter(sub -> sub.getValue().equals("GOOD")) // GOOD values only
                .collect(Collectors.toList()) // make List<Map.Entry>
            ));
地图映射列表
=myMap.entrySet().stream()
.filter(e->e.getValue().containsValue(“GOOD”)//至少需要一个GOOD
.collect(collector.toMap)(
Map.Entry::getKey,//保留原始密钥
e->e.getValue().entrySet().stream()//实际转换
.filter(sub->sub.getValue().equals(“GOOD”)//仅限GOOD值
.collect(Collectors.toList())//制作列表
));

我不得不问,为什么你要从这样一个精心设计的代码开始?一个EnumMap的映射,你想制作一个映射条目列表的映射?拥有合适的对象不是更好吗?实际数据来自一个CSV文件,该文件按服务组织在最顶层,然后在每个服务中,EnumMap参数实际上是映射从固定设备类型到其相应的IP地址字符串,例如,CSV是固定的,不会拆分为单独的表。这样,上面的(e->e.getKey())仍将是相同的高级服务名称密钥(在我设计的示例中,服务名称为KEY1和KEY2)当然可以,但让CSV的一行用实际类型表示要简单得多。创建一个类
服务
,其中包含一个名称和一个包含设备类型、地址等内容的列表(需要更好的名称)。我不清楚最终结果应该是什么样的。最终结果应该是{“KEY1”、{{Parameter.Bar,“GOOD”}},{“KEY2”,{{Parameter.Bar,“GOOD”},{Parameter.Baz,“GOOD”}}非常好,只是一个小问题,在我的实际数据中,我在myMap中有一些整行没有匹配的条目-上面在mapList中有一个带有空值的条目,我将如何过滤这些条目-请原谅我的新手问题,因为我对流API是新的。我通过检查v.entrySe了解了如何只插入非空值t().stream().filter(…),在我的例子中,这是forEach((k,v)->{List ports=v.entrySet().stream().filter(e->!e.getValue().equals(“0:00”).collect(Collectors.toList());if(!ports.isEmpty())portInfo.put(k,validport);})是的,但是它works@johnco3我想提出同样的建议。我正在寻找一种更好的方法,但我认为这是最好的方法。谢谢Jorn,无论哪种方法都很可怕,顺便说一句,我想知道你是否认为不使用单独的mapList变量,而是以一种流的方式一行一行地完成这项工作是可能的。Jus我并不好奇。@johnco3我看了一下,但是空列表也会有同样的问题,只能通过对条目进行两次传递来解决,而不仅仅是现在的一次。