简体   繁体   English

使用Java 8进行过滤:地图 <String, Set<Object> &gt;从地图 <String, Set<Object> &gt;基于对象的属性

[英]Filtering with Java 8: Map<String, Set<Object>> from Map<String, Set<Object>> based on an attribute of Object

This is class Item. 这是类Item。

public class Item {
    String id;
    String name;
    Integer value;
    Boolean status;
}

I have a Map(String, Set(Item)). 我有一个Map(String,Set(Item))。 I want to write a method that returns a Map(String, Set(Item)) such that only Items with status = false or status = null are present in the resulting map. 我想编写一个返回Map(String,Set(Item))的方法,以使结果映射中仅包含status = false或status = null的Items。 I don't want a set-wide operation. 我不要设置范围内的操作。 I want the resulting subsets to only contain those Item that have status == Boolean.FALSE OR status == null. 我希望结果子集仅包含状态== Boolean.FALSE或状态== null的那些项。 I don't want the entire set to get included or excluded. 我不希望整个集合都包含在内或排除在外。 I only want those individual items included or excluded as per the status value. 我只希望根据状态值包括或排除那些单独的项目。

Here's what I've tried so far. 到目前为止,这是我尝试过的。

public Map<String,Set<Item>> filterByStatus(Map<String, Set<Item>> changes) {
    return changes.entrySet()
                  .stream()
                  .filter(p -> p.getValue()
                                .stream()
                                .anyMatch(item -> BooleanUtils.isNotTrue(item.isStatus())))
                  .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
}

It didn't work! 没用! I get back the same results as I would if I didn't call filterByStatus. 我得到的结果与不调用filterByStatus时得到的结果相同。

UPDATE UPDATE

public Map<String,Set<Item>> filterByStatus(Map<String, Set<Item>> changes) {
    return changes.entrySet()
                  .stream()
                  .map(p -> p.getValue()
                                .stream()
                                .filter(item -> BooleanUtils.isNotTrue(item.isStatus())))
                  .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
}

Result: There's an error in the collect(Collectors.toMap()) line saying Non-static method cannot be referenced from static context. 结果:collect(Collectors.toMap())行中出现错误,表明无法从静态上下文中引用非静态方法。

public Map<String, Set<Item>> filterByStatus(Map<String, Set<Item>> changes) {
    return changes.entrySet()
            .stream()
            .collect(Collectors.toMap(Map.Entry::getKey, entry ->
                entry.getValue()
                    .stream()
                    .filter(item -> item.status == null || item.status == Boolean.FALSE)
                    .collect(Collectors.toSet())
            ));
}

Alternatively to a Stream solution, you may use 除了Stream解决方案,您可以使用

public Map<String, Set<Item>> filterByStatus(Map<String, Set<Item>> changes) {
    Map<String, Set<Item>> result = new HashMap<>(changes);
    result.replaceAll((key, set) -> {
        set = new HashSet<>(set);
        set.removeIf(item -> Boolean.TRUE.equals(item.status));
        return set;
    });
    // if you want to remove empty sets afterwards:
    result.values().removeIf(Set::isEmpty);
    return result;
}

You could even do the operation in-place if the sets are mutable and you don't need the old state anymore: 如果集合是可变的并且您不再需要旧状态,您甚至可以就地进行操作:

changes.values().forEach(set -> set.removeIf(item -> Boolean.TRUE.equals(item.status)));
// if you want to remove empty sets afterwards (and the map is mutable):
changes.values().removeIf(Set::isEmpty);

you could even remove these items, followed by removing the set only if they became empty due to the removal, in one statement: 您甚至可以删除这些项,然后仅在一条语句中由于删除而使它们变空的情况下删除该集合:

changes.values().removeIf(set ->
    set.removeIf(item -> Boolean.TRUE.equals(item.status)) && set.isEmpty());

Judging from your description you are looking for allMatch rather than anyMatch . 从您的描述来看,您正在寻找allMatch而不是anyMatch

Currently you get all the sets which contain at least one non-True value. 当前,您获得的所有集合至少包含一个非True值。 What you seem to want is having only sets that consist of non-True values only. 您似乎想要的是仅具有仅包含非True值的集合。

If you are rather looking for filtering out the negative values from all sets, you should use a mapping, not just filter, on the Map. 如果您想从所有集合中滤除负值,则应在Map上使用映射,而不仅仅是过滤。 In the mapping you could create copies of the sets with True values excluded. 在映射中,您可以创建不包含True值的集合的副本。

This avoid include in new Map entrys with 0 items. 这样可以避免将新地图条目包含在0个项目中。

private Map<String,Set<Item>> filterByStatus(Map<String, Set<Item>> changes) {
    return changes.entrySet()
            .stream()
            .filter(entry -> entry.getValue()
                    .stream()
                    .anyMatch(item -> item.status == null || item.status == false))
            .collect(Collectors.toMap(Map.Entry::getKey, entry -> entry.getValue()
                    .stream()
                    .filter(item -> item.status == null || item.status == false)
                    .collect(Collectors.toSet()))
            );
}

如何创建列表<object>带有字段字符串和 Map <string, set<string> &gt; 从另一个列表<object2><div id="text_translate"><p> Class Object2具有标准的 getter 并具有String字段folder 、 file和version 。 它被命名为SourceInfo</p><p> List&lt;SourceInfo&gt; source包含上面提到的三个字段。</p><p> 我的目标是从List&lt;SourceInfo&gt;创建一个List&lt;Info&gt; &gt; 。</p><p> 新List的 class 为Info ,如下图所示。</p><pre> public class Info { private final String folder; private final Map&lt;String, Set&lt;String&gt;&gt; file; public static Builder builder() { return new Builder(); } public static Builder builder(Info info) { return new Builder(info); } private Info(Builder builder) { this.folder = builder.folder; this.file = builder.file; } public String getFolder() { return folder; } public Map&lt;String, Set&lt;String&gt;&gt; getFile() { return file; } // autogenerated toString, hashCode, and equals public static class Builder { private String folder; private Map&lt;String, Set&lt;String&gt;&gt; file; private Builder() {} private Builder(Info info) { this.folder = info.folder; this.file = info.file; } public Builder with(Consumer&lt;Builder&gt; consumer) { consumer.accept(this); return this; } public Builder withFolder(String folder) { this.folder = folder; return this; } public Builder withFile(Map&lt;String, Set&lt;String&gt;&gt; file) { this.file = file; return this; } public Info build() { return new Info(this); } }</pre><p> 到目前为止,我尝试的是在构建器模式中创建一个集合。</p><pre> List&lt;SourceInfo&gt; source; // error: gc overhead limit exceeded List&lt;Info&gt; infoList = source.stream().map(e -&gt; Info.builder().withFolder(e.getFolder()).withFile(source.stream().collect(Collectors.groupingBy(SourceInfo::getKey, Collectors.mapping(SourceInfo::getVersion, Collectors.toSet())))).build()).collect(Collectors.toList()); Map&lt;String, Set&lt;String&gt;&gt; map = source.stream().collect(Collectors.groupingBy(SourceInfo::getKey, Collectors.mapping(SourceInfo::getVersion, Collectors.toSet()))); List&lt;Info&gt; info = source.stream().map(e -&gt; Info.builder().withFolder(e.getFolder()).withFile(map.entrySet().stream().collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue))).build()).collect(Collectors.toList());</pre><p> 所需的 output。 以下语法可能已关闭。</p><pre> // [String, Map&lt;String, Set&lt;String&gt;&gt;] Info [folder, [key=file [value=version]]]...</pre><p> 我是 Java 的新手,不胜感激。</p><p> 我想了解如何使用 java8 和 for 循环来做到这一点。</p><p> 谢谢你。</p></div></object2></string,></object> - How to create a List<Object> with fields String and Map<String, Set<String>> from another List<Object2>

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 从地图转换 <Object,Set<Object> &gt;到地图 <String,Set<String> &gt; - convert from Map<Object,Set<Object>> to Map<String,Set<String>> 比较集<String>带地图<Object>在 Java 8 中获取 Map 值 - Compare Set<String> with Map<Object> to get Map value in Java 8 使用过滤器和流将Map <String,Object>转换为Map <String,Set <Object >> - Convert Map<String, Object> to Map<String, Set<Object>> with filter and streams 放<Object>到地图<String, Set<Long> &gt; java8 - Set<Object> to Map<String, Set<Long>> java8 Java 8流,将对象列表转换为Map <String, Set<String> &gt; - Java 8 streams, convert List of object to Map<String, Set<String>> 地图<String, Object>从列表<Object>带有对象的设置属性 - Map<String, Object> from List<Object> with setting attribute of object Junit 测试 Map <string, set<object> &gt;</string,> - Junit test for Map<String, Set<Object>> 从CharSequence更改为Set的String <CharSequence> 和地图 <CharSequence, Object> - Change from CharSequence to String for Set<CharSequence> & Map<CharSequence, Object> 如何获取列表<Map<String,Object> &gt; 从 Hibernate 的结果集中? - How to get List<Map<String,Object>> from the result set of Hibernate? 如何创建列表<object>带有字段字符串和 Map <string, set<string> &gt; 从另一个列表<object2><div id="text_translate"><p> Class Object2具有标准的 getter 并具有String字段folder 、 file和version 。 它被命名为SourceInfo</p><p> List&lt;SourceInfo&gt; source包含上面提到的三个字段。</p><p> 我的目标是从List&lt;SourceInfo&gt;创建一个List&lt;Info&gt; &gt; 。</p><p> 新List的 class 为Info ,如下图所示。</p><pre> public class Info { private final String folder; private final Map&lt;String, Set&lt;String&gt;&gt; file; public static Builder builder() { return new Builder(); } public static Builder builder(Info info) { return new Builder(info); } private Info(Builder builder) { this.folder = builder.folder; this.file = builder.file; } public String getFolder() { return folder; } public Map&lt;String, Set&lt;String&gt;&gt; getFile() { return file; } // autogenerated toString, hashCode, and equals public static class Builder { private String folder; private Map&lt;String, Set&lt;String&gt;&gt; file; private Builder() {} private Builder(Info info) { this.folder = info.folder; this.file = info.file; } public Builder with(Consumer&lt;Builder&gt; consumer) { consumer.accept(this); return this; } public Builder withFolder(String folder) { this.folder = folder; return this; } public Builder withFile(Map&lt;String, Set&lt;String&gt;&gt; file) { this.file = file; return this; } public Info build() { return new Info(this); } }</pre><p> 到目前为止,我尝试的是在构建器模式中创建一个集合。</p><pre> List&lt;SourceInfo&gt; source; // error: gc overhead limit exceeded List&lt;Info&gt; infoList = source.stream().map(e -&gt; Info.builder().withFolder(e.getFolder()).withFile(source.stream().collect(Collectors.groupingBy(SourceInfo::getKey, Collectors.mapping(SourceInfo::getVersion, Collectors.toSet())))).build()).collect(Collectors.toList()); Map&lt;String, Set&lt;String&gt;&gt; map = source.stream().collect(Collectors.groupingBy(SourceInfo::getKey, Collectors.mapping(SourceInfo::getVersion, Collectors.toSet()))); List&lt;Info&gt; info = source.stream().map(e -&gt; Info.builder().withFolder(e.getFolder()).withFile(map.entrySet().stream().collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue))).build()).collect(Collectors.toList());</pre><p> 所需的 output。 以下语法可能已关闭。</p><pre> // [String, Map&lt;String, Set&lt;String&gt;&gt;] Info [folder, [key=file [value=version]]]...</pre><p> 我是 Java 的新手,不胜感激。</p><p> 我想了解如何使用 java8 和 for 循环来做到这一点。</p><p> 谢谢你。</p></div></object2></string,></object> - How to create a List<Object> with fields String and Map<String, Set<String>> from another List<Object2>
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM