Java Map,使用values属性过滤

时间:2012-06-22 16:30:40

标签: java map filter

我有一个

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

我想过滤并仅保留值包含已知对的条目,让我们说('mike'=&gt;'jordan'),并避免像下面这样的循环

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

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

6 个答案:

答案 0 :(得分:10)

您可以使用Guava和Predicate界面中的过滤器。

Predicate<T> yourFilter = new Predicate<T>() {
    public boolean apply(T o) {
        // your filter
    }
};

所以,简单的例子是:

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);

答案 1 :(得分:4)

不是强迫您的客户端代码使用过滤器/循环,而是在您的类的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
    }
}

顺便说一句,如果您使用循环,请考虑更改为:

for (Iterator<Map.Entry<String, TreeMap<String, String>>> i = resMap.entrySet().iterator(); i.hasNext();) {
    Map.Entry<String, TreeMap<String, String>> entry = i.next();
    if (value.equals(entry.getValue().get(key))) {
        i.remove();
    }
}

循环的变化是:

  • 改变等于的顺序以避免NPE
  • 使用iterator直接删除条目

即使你没有一个类,你也可以轻松地将它包装在一个实用程序类的静态方法中,在那里它也可以很容易地参数化以适用于任何嵌套的地图:

public static <K1, K2, V> void filter(Map<K1, Map<K2, V>> map, K2 key, V value) {
    // Some impl here
}

这是静态方法的非番石榴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();
    }
}

答案 2 :(得分:0)

查看GuavaPredicatesFunctions

答案 3 :(得分:0)

以下是两个例子。两者都根据值的属性匹配打印密钥。

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");
}

一个使用循环,一个使用Guava。

虽然第一个表现更好,但您应该确定哪个是最容易理解和维护的。

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

  1. 很多代码重复。
  2. 特殊情况处理。
  3. 更多圈复杂度。
  4. 前三发子弹导致错误发生的可能性更大。
  5. 很难遵守代码。
  6. 想象一下,您是一名必须支持该软件的新开发人员。你宁愿面对哪一个?

答案 4 :(得分:0)

您可以使用java 8和流过滤地图。此过程的第一步是使用entrySet().stream()转换为流。这会给你一个Stream<Map.Entry<String, TreeMap<String, String>>。然后,您可以使用filter(...)过滤列表。过滤时,如果传入值应包含在过滤结果中,则应返回true。过滤结果后,可以使用foreach循环遍历最终结果。

最终结果如下所示:

resMap.entrySet().stream()
      .filter(e -> el.getValue().get("mike").equals("jordan"))
      .foreach(e -> {
        // Do something with your entry here
      });

答案 5 :(得分:0)

From @Ferrybig answer in this post.

您可以为此使用Java 8方法Collection.removeIf

map.values().removeIf(Object o -> o.get("mike").equals("jordan"));

这将删除所有与谓词匹配的值。

Online demo

这是通过以下事实进行的:为HashMap调用.values()会返回一个集合,该集合将修改委托给HashMap本身,这意味着我们对removeIf()的调用实际上会更改HashMap(此操作无效在所有Java地图上)