Java映射,带值属性的筛选器

Java映射,带值属性的筛选器,java,map,filter,Java,Map,Filter,我有一个 TreeMap resMap new TreeMap<String, Map<String, String>>(); TreeMap resMap new TreeMap(); 我只想过滤和保留那些值包含已知对的条目,比如('mike'=>'jordan'),并避免下面这样的循环 在我包含的库apache.commons和google.common中是否有一个过滤器方法(这可能也会做一个循环,但至少不那么冗长) for (Entry<String,

我有一个

TreeMap resMap new TreeMap<String, Map<String, String>>(); 
TreeMap resMap new TreeMap();
我只想过滤和保留那些值包含已知对的条目,比如('mike'=>'jordan'),并避免下面这样的循环

在我包含的库apache.commons和google.common中是否有一个过滤器方法(这可能也会做一个循环,但至少不那么冗长)

for (Entry<String, TreeMap<String, String>> el : resMap.entrySet()){
    if (el.getValue().get("mike").equals("jordan")){
        //
    }
}
for(条目el:resMap.entrySet()){
如果(el.getValue().get(“mike”).equals(“jordan”)){
//
}
}

看看的和。

您可以使用番石榴的过滤器和
谓词
界面

Predicate<T> yourFilter = new Predicate<T>() {
    public boolean apply(T o) {
        // your filter
    }
};
谓词yourFilter=新谓词(){
公共布尔应用(TO){
//你的过滤器
}
};
因此,简单的例子是:

Predicate<Integer> evenFilter = new Predicate<Integer>() {
    public boolean apply(Integer i) {
        return (i % 2 == 0);
    }
};

Map<Integer, Integer> map = new HashMap<Integer, Integer>();

Map<Integer, Integer> evenMap = Maps.filterValues(map, evenFilter);
Predicate evenFilter=新谓词(){
公共布尔应用(整数i){
返回(i%2==0);
}
};
Map Map=newhashmap();
Map evenMap=Maps.filterValues(Map,evenFilter);

不要强迫客户端代码使用过滤器/循环,而是将所需内容构建到类的API中:

public class MyClass {

    private TreeMap resMap new TreeMap<String, Map<String, String>>();

    public void filter(String key, String value) {
        // Some impl here. Either your loop or the guava approach
    }
}
以下是静态方法的非番石榴impl:

for (Iterator<Map.Entry<K1, Map<K2, V>>> i = map.entrySet().iterator(); i.hasNext();) {
    Map.Entry<K1, Map<K2, V>> entry = i.next();
    if (value.equals(entry.getValue().get(key))) {
        i.remove();
    }
}
for(迭代器i=map.entrySet().Iterator();i.hasNext();){
Map.Entry=i.next();
if(value.equals(entry.getValue().get(key))){
i、 删除();
}
}

以下是两个示例。这两个示例都基于值属性中的匹配来打印键

private static void printMatchingEntriesUsingALoop(Map<String, Map<String, String>> resMap, String key, String value) {
    for (Map.Entry<String, Map<String, String>> entry : resMap.entrySet())
        if (value.equals(entry.getValue().get(key)))
            System.out.println(entry.getKey());
}

private static void printMatchingEntriesUsingGuava(Map<String, Map<String, String>> resMap, final String key, final String value) {
    Predicate<Map<String, String>> keyValueMatch = 
    new Predicate<Map<String, String>>() {
        @Override
        public boolean apply(@Nullable Map<String, String> stringStringMap) {
            return value.equals(stringStringMap.get(key));
        }
    };

    Maps.EntryTransformer<String, Map<String, String>, Void> printKeys = 
    new Maps.EntryTransformer<String, Map<String, String>, Void>() {
        @Override
        public Void transformEntry(@Nullable String s, 
                 @Nullable Map<String, String> stringStringMap) {
            System.out.println(s);
            return null;
        }
    };

    Maps.transformEntries(Maps.filterValues(resMap, keyValueMatch), printKeys);
}

public static void main(String... args) {
    Map<String, Map<String, String>> resMap = new TreeMap<String, Map<String, String>>();
    printMatchingEntriesUsingALoop(resMap, "first", "mike");
    printMatchingEntriesUsingGuava(resMap, "first", "mike");
}
private static void printMatchingEntriesUsingALoop(映射resMap,字符串键,字符串值){
对于(Map.Entry:resMap.entrySet())
if(value.equals(entry.getValue().get(key)))
System.out.println(entry.getKey());
}
私有静态void printmachingentriesusingGuava(映射resMap,最终字符串键,最终字符串值){
谓词keyValueMatch=
新谓词(){
@凌驾
公共布尔应用(@Nullable Map StringMap){
返回值.equals(stringmap.get(key));
}
};
Maps.EntryTransformer打印密钥=
新的Maps.EntryTransformer(){
@凌驾
public Void transformEntry(@Nullable String s,
@可为空的映射(字符串映射){
系统输出打印项次;
返回null;
}
};
Maps.transformEntries(Maps.FilterValue(resMap、keyValueMatch)、printKeys);
}
公共静态void main(字符串…参数){
Map resMap=newtreemap();
打印匹配使用循环(resMap,“first”,“mike”);
使用番石榴(resMap,“first”,“mike”);
}
一个用环,一个用番石榴

虽然第一个性能更好,但您应该真正决定哪一个最容易理解和维护

@missingfaktor的一些建议。你必须使用自己的判断,但他很好地强调了一些问题

  • 大量代码重复
  • 特殊案件处理
  • 更多圈复杂度
  • 由于前三发子弹,出错的几率更大
  • 难以理解的代码

  • 假设您是一名必须支持此软件的新开发人员。您更愿意面对哪一个?

    您可以使用java 8和streams过滤地图。此过程的第一步是使用
    entrySet().stream()
    。这将为您提供

    为此,您可以使用Java 8方法:

    map.values().removeIf(Object o -> o.get("mike").equals("jordan"));
    
    这将删除与谓词匹配的所有值


    这是因为为HashMap调用
    .values()
    会返回一个集合,该集合将修改委托回HashMap本身,这意味着对
    removeIf()
    的调用实际上会更改HashMap(这并不适用于所有java Map)

    您需要某种类似于Java的DotNet的LINQ…为什么要避免循环?您使用的任何东西都像是在为您使用循环。次要注释:在等号中切换顺序,因为get(“mike”)可能返回null。即
    if(“jordan”).equals(el.getValue().get(“mike”)
    @PeterLawrey,“你使用的任何东西都像是在为你使用循环。”这是一个毫无意义的论点。这个类比可能有助于理解为什么会这样:“我想避免goto指令。$lang支持正确的循环吗?”“你为什么想要循环?他们无论如何都可能在内部使用goto。”。“就像这样,你可以一直到原始位。@missingfaktor有很多理由避免
    goto
    ,但是因为你不喜欢它们而避免它们不是其中之一。很自然!它们还可以从用户代码中删除重复的循环。并用比它们所替换的循环更长的谓词替换它们。”@PeterLawrey但谁在乎性能是否正常。它使您的基础更小,语义更容易理解。它还可以让您抽象地处理数据,让实现来决定如何/过滤什么。我要明确的是,我也认为OP提出了错误的问题,这不是一种方式,但无论如何它是正确的公平地说,没有meritWell,这些都是返回视图。@Bohemian总是让我困惑的是需要用更复杂的东西来替换循环。循环通常是最短、最干净的方法。它可以稍微快一点,但正如你所说,在大多数情况下这并不重要。@EugeneKuleshov很好,但这是一种实现选择。这个答案的主要目的是提供一个API,这样客户机代码就不需要了解guava/循环等。我编辑了这个答案来说明这一点。@EugeneKuleshov不是重新发明循环,而是使用一个语言构造的循环。;)@PeterLawrey你意识到你的评论可以被循环替换吗?@EugeneKuleshov你的意思是我的陈述是自我引用的吗?我认为,尽管番石榴过滤器需要相同的时间,不管是较大还是较小的贴图,但对小尺寸的贴图使用迭代将提供更好的性能。
    private static void printMatchingEntriesUsingALoop(Map<String, Map<String, String>> resMap, String key, String value) {
        for (Map.Entry<String, Map<String, String>> entry : resMap.entrySet())
            if (value.equals(entry.getValue().get(key)))
                System.out.println(entry.getKey());
    }
    
    private static void printMatchingEntriesUsingGuava(Map<String, Map<String, String>> resMap, final String key, final String value) {
        Predicate<Map<String, String>> keyValueMatch = 
        new Predicate<Map<String, String>>() {
            @Override
            public boolean apply(@Nullable Map<String, String> stringStringMap) {
                return value.equals(stringStringMap.get(key));
            }
        };
    
        Maps.EntryTransformer<String, Map<String, String>, Void> printKeys = 
        new Maps.EntryTransformer<String, Map<String, String>, Void>() {
            @Override
            public Void transformEntry(@Nullable String s, 
                     @Nullable Map<String, String> stringStringMap) {
                System.out.println(s);
                return null;
            }
        };
    
        Maps.transformEntries(Maps.filterValues(resMap, keyValueMatch), printKeys);
    }
    
    public static void main(String... args) {
        Map<String, Map<String, String>> resMap = new TreeMap<String, Map<String, String>>();
        printMatchingEntriesUsingALoop(resMap, "first", "mike");
        printMatchingEntriesUsingGuava(resMap, "first", "mike");
    }
    
    resMap.entrySet().stream()
          .filter(e -> el.getValue().get("mike").equals("jordan"))
          .foreach(e -> {
            // Do something with your entry here
          });
    
    map.values().removeIf(Object o -> o.get("mike").equals("jordan"));