如何测试数组是否包含map中的每个值?

时间:2017-10-23 14:43:29

标签: java arrays hashmap

我有一张地图:

Map<String, String> abc = new HashMap<>();
  

&#34; KEY1&#34; :&#34; value1&#34;,
  &#34; KEY2&#34; :&#34; value2&#34;

一个数组:

String[] options= {"value1", "value2", "value3"}

我正在创建这个数组如下(我正在使用以下方法做一些与我在这里问的问题无关的其他方法):

public String[] getOptions() {
    List<String> optionsList = getOptionsFromAMethod(WebElementA);
    String[] options = new String[optionsList.size()];
    options = optionsList.toArray(options);
    return options;
}

验证String []是否包含Map中的每个值的最佳方法是什么?

我正在考虑这样做:

for (Object value : abc.values()) {
    Arrays.asList(options).contains(value);
}

3 个答案:

答案 0 :(得分:2)

说明

您当前的方法会创建一个ArrayList(来自java.util.Arrays,而不是与来自java.util的常规ArrayList混淆)包装给定的数组

然后,为地图的每个值调用ArrayList#contains方法。但是这种方法非常慢。它遍历整个列表以搜索某些内容。

因此,您当前的方法产生的O(n^2)不能很好地扩展。

解决方案

我们可以通过使用专为快速contains查询设计的数据结构做得更好,即HashSet

因此,我们不会将所有值都放入ArrayList,而是将HashSet方法快速:{/ 1>

contains

代码现在可以在boolean doesContainAll = true; HashSet<String> valuesFromArray = new HashSet<>(Arrays.asList(options)); for (String value : abc.values()) { if (!valuesFromArray.contains(value)) { doesContainAll = false; break; } } // doesContainAll now is correctly set to 'true' or 'false' 中使用,在复杂性方面更好最佳

当然,您可以通过常数因素进一步优化以加速。例如,您可以先检查尺寸,如果O(n)大于options.length,那么您可以直接返回abc.values().size()

JStream解决方案

你也可以使用 Java 8 false来简化上面的代码,结果以及幕后的程序是一样的:

Stream

ArrayList#的见解包含

让我们仔细研究HashSet<String> valuesFromArray = new HashSet<>(Arrays.asList(options)); boolean doesContainAll = abc.values().stream() .allMatch(valuesFromArray::contains); 。您可以找到它的代码here

以下是java.util.Arrays.ArrayList方法的代码:

contains

让我们看看如何实施public boolean contains(Object o) { return indexOf(o) != -1; }

indexOf

实际上,在所有情况下,该方法都将通过源数组从左到右遍历以查找对象。 没有花哨的方法能够直接访问信息是否 对象,它在public int indexOf(Object o) { E[] a = this.a; if (o == null) { for (int i = 0; i < a.length; i++) if (a[i] == null) return i; } else { for (int i = 0; i < a.length; i++) if (o.equals(a[i])) return i; } return -1; } 而不在O(n)中运行。

关于重复的注释

如果您的任何一个数据可能包含重复项并且您计划单独计算,那么您将需要稍微不同的方法,因为O(1)不会打扰对于重复数量。

为此,您可以先将contains收集到abc.values()中。然后,每次检查元素时,都会从List中删除匹配的元素。

或者,您可以设置一个List来计算其出现的每个元素。然后,每次检查一个元素时,将计数器减一。

答案 1 :(得分:1)

您可以使用https://docs.oracle.com/javase/7/docs/api/java/util/List.html#containsAll(java.util.Collection)

Arrays.asList("value1", "value2", "value3").containsAll(abc.values())

答案 2 :(得分:0)

我建议使用一个流:

final List<String> optionsList = Arrays.asList(options);
abc.values().stream().allMatch(optionsList::contains);