我有一个包含以下值的String[]
:
public static final String[] VALUES = new String[] {"AB","BC","CD","AE"};
给定字符串 s
,是否有一种好的方法来测试 VALUES
是否包含 s
?
Arrays.asList(yourArray).contains(yourValue)
警告:对于基本类型的数组无效(请参见注释)。
String[] values = {"AB","BC","CD","AE"};
boolean contains = Arrays.stream(values).anyMatch("s"::equals);
要检查一个包含int
、double
或long
值的数组是否包含某个值,分别使用IntStream
、DoubleStream
或LongStream
。
int[] a = {1,2,3,4};
boolean contains = IntStream.of(a).anyMatch(x -> x == 4);
ArrayList
,但不是你期望的java.util.ArrayList
,实际返回的类是:java.util.Arrays.ArrayList<E>
,定义为:public class java.util.Arrays {private static class ArrayList<E> ... {}}
。 - TWiStErRob引用数组不太好。对于这种情况,我们需要一个集合。自 Java SE 9 版本以来,我们有了 Set.of
方法。
private static final Set<String> VALUES = Set.of(
"AB","BC","CD","AE"
);
VALUES.contains(s)
O(1).
这是最佳类型,不可变的、O(1)和简明的。太美妙了。
首先清除代码。我们有(已更正):
public static final String[] VALUES = new String[] {"AB","BC","CD","AE"};
这是一个可变的静态变量,FindBugs会告诉你这是非常不好的。不要修改静态变量,也不要允许其他代码这样做。至少,该字段应该是私有的:
private static final String[] VALUES = new String[] {"AB","BC","CD","AE"};
new String[];
部分。)private static final Set<String> VALUES = new HashSet<String>(Arrays.asList(
new String[] {"AB","BC","CD","AE"}
));
(像我这样的多疑者可能会更放心,如果这被包装在Collections.unmodifiableSet
中 - 它甚至可以被公开。)
(为了更符合品牌形象,集合API可预测地仍然缺少不可变集合类型,并且语法对我来说仍然过于冗长。)
Arrays.asList
的调用生成的由数组支持的ArrayList)? - Basil BourqueTreeSet
的时间复杂度为 O(log n)
。HashSet
的桶的平均元素数量大致恒定,至少在数组大小不超过 2^30
的情况下是如此。可能会受到硬件缓存等因素的影响,这些都会被大 O 分析所忽略。此外还需要假设哈希函数能有效地工作。 - Tom Hawtin - tackline你可以使用Apache Commons Lang中的ArrayUtils.contains
public static boolean contains(Object[] array, Object objectToFind)
请注意,如果传递给方法的数组为null
,则该方法将返回false
。
还有可用于各种基本类型数组的方法。
String[] fieldsToInclude = { "id", "name", "location" };
if ( ArrayUtils.contains( fieldsToInclude, "id" ) ) {
// Do some stuff.
}
只需手动实现即可:
public static <T> boolean contains(final T[] array, final T v) {
for (final T e : array)
if (e == v || v != null && v.equals(e))
return true;
return false;
}
改进:
方法内的v != null
条件是固定的,调用该方法时它总是评估为相同的布尔值。因此,如果输入的array
很大,只评估一次这个条件更有效,并且我们可以基于结果在for
循环内使用简化/更快的条件。改进后的contains()
方法:
public static <T> boolean contains2(final T[] array, final T v) {
if (v == null) {
for (final T e : array)
if (e == null)
return true;
}
else {
for (final T e : array)
if (e == v || v.equals(e))
return true;
}
return false;
}
Collection.contains(Object)
。 - Steve KuoArrays
和ArrayList
的源代码,就会发现这并不一定比使用Arrays.asList(...).contains(...)
更快。创建ArrayList
的开销非常小,而ArrayList.contains()
使用比上面显示的循环更智能的循环(实际上使用了两个不同的循环)(JDK 7)。 - Axel使用 List
:
public static boolean useList(String[] arr, String targetValue) {
return Arrays.asList(arr).contains(targetValue);
}
使用Set
:
public static boolean useSet(String[] arr, String targetValue) {
Set<String> set = new HashSet<String>(Arrays.asList(arr));
return set.contains(targetValue);
}
使用简单循环:
public static boolean useLoop(String[] arr, String targetValue) {
for (String s: arr) {
if (s.equals(targetValue))
return true;
}
return false;
}
使用Arrays.binarySearch()
:
以下代码是错误的,这里列出仅供完整性。 binarySearch()
只能用于已排序的数组。您会发现下面的结果很奇怪。当数组已排序时,这是最佳选择。
public static boolean binarySearch(String[] arr, String targetValue) {
return Arrays.binarySearch(arr, targetValue) >= 0;
}
String testValue="test";
String newValueNotInList="newValue";
String[] valueArray = { "this", "is", "java" , "test" };
Arrays.asList(valueArray).contains(testValue); // returns true
Arrays.asList(valueArray).contains(newValueNotInList); // returns false
return Arrays.asList(ints).contains(k);
- Willians Martins如果数组没有排序,你需要迭代整个数组并对每个元素调用equals方法。
如果数组已经排序,你可以使用二分查找,在Arrays类中有一个实现。
一般来说,如果你需要进行很多成员检查,可能会更好地将所有元素存储在Set中,而不是数组中。
就我的经验而言,我进行了一个速度比较的测试。我生成随机整数,将它们转换为字符串并将它们添加到数组中。然后我搜索可能的最大数字/字符串,这将是asList().contains()
的最坏情况。
当使用10K数组大小时,结果如下:
Sort & Search : 15
Binary Search : 0
asList.contains : 0
使用100K数组的结果如下:
Sort & Search : 156
Binary Search : 0
asList.contains : 32
因此,如果数组是按排序顺序创建的,则二分搜索是最快的方法;否则,asList().contains
将是更好的选择。如果您有许多搜索,则对数组进行排序可能是值得的,以便您可以使用二分搜索。这完全取决于您的应用程序。
我认为这些是大多数人所期望的结果。以下是测试代码:
import java.util.*;
public class Test {
public static void main(String args[]) {
long start = 0;
int size = 100000;
String[] strings = new String[size];
Random random = new Random();
for (int i = 0; i < size; i++)
strings[i] = "" + random.nextInt(size);
start = System.currentTimeMillis();
Arrays.sort(strings);
System.out.println(Arrays.binarySearch(strings, "" + (size - 1)));
System.out.println("Sort & Search : "
+ (System.currentTimeMillis() - start));
start = System.currentTimeMillis();
System.out.println(Arrays.binarySearch(strings, "" + (size - 1)));
System.out.println("Search : "
+ (System.currentTimeMillis() - start));
start = System.currentTimeMillis();
System.out.println(Arrays.asList(strings).contains("" + (size - 1)));
System.out.println("Contains : "
+ (System.currentTimeMillis() - start));
}
}
你可以使用Arrays.asList方法,以类似的方式直接将其初始化为List,而不是使用快速数组初始化语法,例如:
public static final List<String> STRINGS = Arrays.asList("firstString", "secondString" ...., "lastString");
那么你可以这样做(就像上面的例子):
STRINGS.contains("the string you want to find");
使用Java 8,您可以创建一个流并检查流中的任何条目是否与"s"
匹配:
String[] values = {"AB","BC","CD","AE"};
boolean sInArray = Arrays.stream(values).anyMatch("s"::equals);
或者作为通用方法:
public static <T> boolean arrayContains(T[] array, T value) {
return Arrays.stream(array).anyMatch(value::equals);
}
anyMatch
的 JavaDoc 表示它“如果不必要确定结果,则可能不会对所有元素评估谓词”,因此在找到匹配项后可能不需要继续处理。 - mkobit您可以使用 Arrays类 执行二分查找。如果您的数组未排序,您需要使用同一类中的排序函数对数组进行排序,然后通过它来搜索。
java.util.Arrays
中找到一个简单的indexOf
和contains
,它们都包含直接的循环。是的,你可以在1分钟内编写它们;但我仍然去了StackOverflow,期望在JDK的某个地方找到它们。 - tucuxi