我有一个
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")){
//
}
}
答案 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();
}
}
循环的变化是:
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)
答案 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的一些建议。你必须使用自己的判断,但他很好地强调了一些问题。
想象一下,您是一名必须支持该软件的新开发人员。你宁愿面对哪一个?
答案 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"));
这将删除所有与谓词匹配的值。
这是通过以下事实进行的:为HashMap调用.values()
会返回一个集合,该集合将修改委托给HashMap本身,这意味着我们对removeIf()
的调用实际上会更改HashMap(此操作无效在所有Java地图上)