Efficient way to find if map contains any of the k

2019-02-12 17:21发布

问题:

I need to check if map contains any of the keys from a list, and if it does then return the first matching value. The naive approach that comes to mind is to do it in two nested loops:

Map<String, String> fields = new HashMap<String, String>();
fields.put("a", "value a");
fields.put("z", "value z");
String[] candidates = "a|b|c|d".split("|");
for (String key : fields.keySet()){
    for (String candidate : candidates) {
        if (key.equals(candidate)){
            return fields.get(key);
        }
    }
}

Is there a nicer and more efficient way, possibly one relying on the Java standard library?

回答1:

Surely something like:

for (String candidate : candidates) {
     String result = fields.get(key);
     if (result != null) {
         return result;
     }
}

The above only performs one map lookup per candidate key. It avoids the separate test for presence plus extraction, since extracting a non-existant key will simply give you a null. Note (thanks Slanec) that a null value for a valid key is indistinguishable from a non-existant key for this solution.

I don't quite understand why you're performing the case conversion, btw.



回答2:

for(String candidate : candidates) {
 if(fields.containsKey(candidate)) {
  return fields.get(candidate)
 }
}

the best way if null values are possibly in map, and if only the first detected key is required.



回答3:

My take:

Map<String, String> fields = new HashMap<String, String>();
fields.put("a", "value a");
fields.put("z", "value z");
String[] candidates = "a|b|c|d".split("|");
for (String candidate : candidates) {
    if (fields.containsKey(candidate)) {
        return fields.get(candidate);
    }
}


回答4:

In Java 8 you can have this:

boolean exists = Arrays.stream(candidates).anyMatch(fields::containsKey);

If you just want to know if any of candidates is key to the map.

If you want to know the first or any you can use:

Arrays.stream(candidates).filter(fields::containsKey).findAny();

or

Arrays.stream(candidates).filter(fields::containsKey).findFirst();

As per @Klapsa2503 answer above



回答5:

Try

Set<String> keySet = new HashSet<String>(fields.keySet());    
keySet.retainAll(list);

so keySet is supposed to have all keys from HashMap which are mentioned in the list



回答6:

In Java 8 you can use this:

return candidates.stream()
            .filter(fields::containsKey)
            .findFirst()
            .map(fields::get)
            .orElse(null);


回答7:

Try as

    List list= Arrays.asList(1, 2, 3);
    HashMap map = new HashMap();
    map.put(1, 1);
    map.put(3, 3);
    Set set = new HashSet(map.keySet());
    set.retainAll(list);
    System.out.println(set);
    Object e = set.isEmpty() ? null : set.iterator().next();
    System.out.println(e);

output

[1, 3]
1


回答8:

Map<String, String> fields = new HashMap<String, String>();
fields.put("a", "value a");
fields.put("z", "value z");
String[] candidates = "a|b|c|d".split("|");
List<String> canList = Arrays.asList(candidates );
for (String key : fields.keySet()){

if (canList .contains(key)) {
return fields.get(key);
}

}


回答9:

You can use a single loop if you assume the key of the map are already in lower case, in the same way you assume the lookup values are in lower case.