查找映射是不是包含列表/可迭代项中的任何键的有效方法

Posted

技术标签:

【中文标题】查找映射是不是包含列表/可迭代项中的任何键的有效方法【英文标题】:Efficient way to find if map contains any of the keys from a list/iterable查找映射是否包含列表/可迭代项中的任何键的有效方法 【发布时间】:2012-12-13 15:49:38 【问题描述】:

我需要检查一个映射是否包含列表中的任何键,如果包含则返回第一个匹配值。想到的幼稚方法是在两个嵌套循环中进行:

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

有没有更好更有效的方法,可能依赖于 Java 标准库?

【问题讨论】:

【参考方案1】:
for(String candidate : candidates) 
 if(fields.containsKey(candidate)) 
  return fields.get(candidate)
 

如果 null 值可能在 map 中,并且只需要第一个检测到的键,则最好的方法。

【讨论】:

【参考方案2】:

肯定是这样的:

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

上面只对每个候选键执行 一个 映射查找。它避免了存在和提取的单独测试,因为提取不存在的键只会给你一个空值。请注意(感谢 Slanec)对于此解决方案,有效键的空值与不存在的键无法区分。

我不太明白你为什么要进行大小写转换,顺便说一句。

【讨论】:

这是尽可能高效的方法,但如果 nullMap 中的允许值,则可能会变得棘手。 有趣...我是否正确理解这个想法是只使用一次map.get() 而不是map.contains() + map.get(),因为这样可以避免第二次查找?这很整洁! @NimChimpsky retainAll 具有描述性。 @ccpizza - 没错。请注意 Slanec 的警告。地图中的空值,但 @ccpizza 实际上,是的,一次,我想。在一个应用程序中,我们没有明确控制 hashmap 的内容,因为它是用户的配置,我们需要捕获设置被访问(但未更改)或重置为默认值的情况。 Anyway, there is a SO question for this.【参考方案3】:

在 Java 8 中你可以这样:

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

如果您只是想知道是否有任何候选人是地图的关键。

如果你想知道第一个或任何你可以使用的:

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

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

根据上面的@Klapsa2503 回答

【讨论】:

【参考方案4】:

我的看法:

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

【讨论】:

【参考方案5】:

在 Java 8 中你可以使用这个:

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

【讨论】:

【参考方案6】:

试试

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

所以keySet 应该具有列表中提到的 HashMap 中的所有键

【讨论】:

我相信这是最短的方法。但是,它可能不是最快的,因为循环在第一个找到的结果处结束,但这会继续工作直到结束。 @Slanec,是的,这取决于 OP 是想要获取所有密钥还是只获取第一个。【参考方案7】:

试一试

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

输出

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



【讨论】:

注意:canList.contains 在时间上是线性的。【参考方案9】:

如果您假设映射的键已经是小写,则可以使用单个循环,就像您假设查找值是小写一样。

【讨论】:

以上是关于查找映射是不是包含列表/可迭代项中的任何键的有效方法的主要内容,如果未能解决你的问题,请参考以下文章

TreeMap中的keySet()方法的功能

Python,查找范围是否包含范围列表中的另一个较小范围

如何将嵌套列表映射到 Python 中的可迭代字典

Python列表操作

我希望在代码上有一个'else'语句,使用'for'和'if'语句迭代通过列表来查找作为字典键的项

仅包含每个重复项中的第一个的 Linq 键