7

我有一个

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

我想过滤并只保留值包含已知对的条目,比如说('mike' => 'jordan'),并避免像下面这样的循环

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

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

6 回答 6

11

您可以使用 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);
于 2012-06-22T16:42:53.457 回答
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
}

这是静态方法的非番石榴实现:

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();
    }
}
于 2012-06-22T17:03:06.277 回答
0

看看Guava谓词函数

于 2012-06-22T16:35:12.963 回答
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. 很难遵循代码。

想象一下,您是一名必须支持该软件的新开发人员。你更愿意面对哪个?

于 2012-06-22T18:21:48.347 回答
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
      });
于 2016-03-14T18:25:41.567 回答
0

来自@Ferrybig 在这篇文章中的回答。

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

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

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

Online demo

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

于 2020-11-06T19:28:09.387 回答