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