Java的地图,与值的属性过滤器(Java Map, filter with values prop

2019-06-25 17:13发布

我有一个

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

我想过滤,只保留条目值包含已知对,比方说(“迈克” =>“乔丹”),并避免象下面这样一个循环

有没有在我的图书馆包括和apache.commons一个google.common滤波方法(也可能会做一个循环太多,但至少它是更简洁

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

Answer 1:

您可以使用番石榴和过滤器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);


Answer 2:

而不是强迫你的客户端代码使用过滤器/循环,建立你需要为你的类的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();
    }
}


Answer 3:

看看番石榴的谓词和功能 。



Answer 4:

这里有两个例子。 根据比赛的价值属性中的打印两者的关键。

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

一个使用一个循环,一个用番石榴。

虽然第一个执行得更好,你应该决定,这将是最容易理解和维护。

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

  1. 很多重复的代码。
  2. 特殊情况的处理。
  3. 更多的圈复杂度。
  4. 错误的更多的机会,因为前三个子弹的结果。
  5. 很难跟随代码。

想象一下,你是新开发谁得支持该软件。 你更愿意面对?



Answer 5:

您可以使用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
      });


文章来源: Java Map, filter with values properties
标签: java map filter