Map<String, List<? extends Object>> Stream API 的过滤问题

问题描述 投票:0回答:2

我有

Employee
对象,其中包含
3
字段:
name
role
companyName

我需要根据

Employee
属性过滤
role
对象。

尽管我在下面的代码中的流中应用了

filter
,但它返回了整个数据。

我的代码:

public static Map<String, List<? extends Employee>> testMappingFilter(List<Employee> emp) {
    Map<String, List<? extends Employee>> dataInput = new HashMap<>();
    for (Employee entry : emp) {
        dataInput.put("senior", new ArrayList(emp));
        dataInput.put("junior", new ArrayList(emp));
    }
    
    Map<String, List<? extends Employee>> dataResponse = new HashMap<>();
    
    Set<String> realmroles = new HashSet<>();
    realmroles.add("admin");
    realmroles.add("user");
    
    Either<Map<String, List<? extends Employee>>, ResponseFormat> followedResourcesServices = Either.left(dataInput);
    
    realmroles.stream().forEach(role -> 
        followedResourcesServices.left().value().entrySet().stream()
                .filter(elements -> elements.getValue().stream().anyMatch(i -> ((Employee) i).getRole().contains(role)))
            .forEach(elements -> dataResponse.put(elements.getKey(), elements.getValue())));
    
    return dataResponse;
}

样本数据:

预期输出:

(预期角色只有

"admin"
"user"
,与角色
"super"
相关的数据应该不会来)

{ “senior” :
   [ { ”name”:”ABC”, “role”:”admin”, “companyName”:”ABC &Co” },
     { ”name”:”XYZ”, “role”:”admin”, “companyName”:”XYZ &Co” },
     { ”name”:”RST”, “role”:”user”, “companyName”:”RST &Co” } ],
  “junior” :
   [ { ”name”:”ABC”, “role”:”admin”, “companyName”:”ABC &Co” },
     { ”name”:”XYZ”, “role”:”admin”, “companyName”:”XYZ &Co” },
     { ”name”:”RST”, “role”:”user”, “companyName”:”RST &Co” } ] 
}

实际产量:

{ “senior” :
   [ { ”name”:”ABC”, “role”:”admin”, “companyName”:”ABC &Co” },
     { ”name”:”DDD”, “role”:”super”, “companyName”:”DDD &Co” },
     { ”name”:”XYZ”, “role”:”admin”, “companyName”:”XYZ &Co” },
     { ”name”:”RST”, “role”:”user”, “companyName”:”RST &Co” } ],
  “junior” :
   [ { ”name”:”ABC”, “role”:”admin”, “companyName”:”ABC &Co” },
     { ”name”:”DDD”, “role”:”super”, “companyName”:”DDD &Co” },
     { ”name”:”XYZ”, “role”:”admin”, “companyName”:”XYZ &Co” },
     { ”name”:”RST”, “role”:”user”, “companyName”:”RST &Co” } ] 
}
java java-stream collectors
2个回答
2
投票

您的代码中有几个问题:

  • 过滤逻辑不正确:您说您只需要保留角色

    "admin"
    "user"
    ,但根据您的代码,
    List
    中的任何
    Employee
    包含至少一名具有这些角色的员工都是好的去(意味着“整个”列表,而不仅仅是具有所需角色的员工)。这就是为什么您会在输出中看到角色 ”super”。您需要过滤每个
    list
    中的employees,而不是过滤lists

  • 这不是
  • Stream.forEach

    的工作,它通过

    副作用
    运作。 不鼓励使用它来代替归约操作。查看 API 文档,特别注意代码示例。

  • 我们可以简单地使用
  • Set

    检查,而不是迭代角色的

    contains()
    ,并仅迭代您通过调用
    Either.left(dataInput).value()
    检索的映射条目。
    
    

  • 为了累积流中的值,我们有多种操作,在这种情况下最合适的是
collect()

,因为我们需要执行可变归约。

在这种情况下,我们无法在不创建新对象的情况下在流中应用过滤逻辑(

这会降低性能

),或者不改变现有数据(即使您不再需要它,这也不是正确的方法,因为改变流中的对象违反了函数式编程范式)。 我们的另一个选择是在累积数据时在

Collector

内执行过滤。我会继续做下去。

为了生成结果图,我们可以使用 

collector

groupingBy()

 与作为下游应用的 
flatMapping()
 + 
toList()
结合使用。
这就是它的实现方式:

Map<String, List<? extends Employee>> dataInput = // initializing dataInput Set<String> realmroles = // initializing realmroles return Either.left().value().entrySet().stream() .collect(Collectors.groupingBy( Map.Entry::getKey, Collectors.flatMapping(entry -> entry.getValue().stream() .filter(emp -> realmroles.contains(((Employee) emp).getRole())), Collectors.toList()) ));



0
投票

followedResourcesServices.left().value().entrySet().stream().forEach(e -> { e.setValue(e.getValue().stream().filter(i -> realmroles.stream().anyMatch(role -> ((Employee) i).getRole().equals(role))). collect(Collectors.toList())); dataResponse.put(e.getKey(), e.getValue()); });

© www.soinside.com 2019 - 2024. All rights reserved.