如何确定数组在 Java 中是否包含特定值?

我有一个String[] ,其值如下所示:

public static final String[] VALUES = new String[] {"AB","BC","CD","AE"};

给定String s ,是否存在测试VALUES是否包含s的好方法?

答案

Arrays.asList(yourArray).contains(yourValue)

警告:这不适用于图元数组(请参见注释)。


您现在可以使用 Streams。

String[] values = {"AB","BC","CD","AE"};
boolean contains = Arrays.stream(values).anyMatch("s"::equals);

要检查intdoublelong数组是否包含值, LongStream分别使用IntStreamDoubleStreamLongStream

int[] a = {1,2,3,4};
boolean contains = IntStream.of(a).anyMatch(x -> x == 4);

Java SE 9 的简要更新

引用数组不好。对于这种情况,我们要紧紧追赶。从 Java SE 9 开始,我们有了Set.of

private static final Set<String> VALUES = Set.of(
    "AB","BC","CD","AE"
);

“给出 String,是否有测试 VALUES 是否包含 s 的好方法?”

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 ,则可能会更放心 - 甚至可以将其公开。)

(* 在品牌上要多说一点,按我的喜好,collection API 仍会缺少不可变的 collection 类型,并且语法仍然太冗长。)

您可以从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;
}

如果数组未排序,则必须遍历所有内容并在每个数组上调用 equals。

如果数组已排序,则可以进行二进制搜索, Arrays类中有一个。

一般来说,如果要进行大量成员资格检查,则可能需要将所有内容存储在 Set 中,而不是存储在数组中。

四种不同的方法检查数组是否包含值

1)使用清单:

public static boolean useList(String[] arr, String targetValue) {
    return Arrays.asList(arr).contains(targetValue);
}

2)使用 Set:

public static boolean useSet(String[] arr, String targetValue) {
    Set<String> set = new HashSet<String>(Arrays.asList(arr));
    return set.contains(targetValue);
}

3)使用一个简单的循环:

public static boolean useLoop(String[] arr, String targetValue) {
    for (String s: arr) {
        if (s.equals(targetValue))
            return true;
    }
    return false;
}

4)使用 Arrays.binarySearch():

下面的代码是错误的,此处出于完整性目的列出了该代码。 binarySearch()仅可用于排序数组。您会发现下面的结果很奇怪。这是对数组进行排序时的最佳选择。

public static boolean binarySearch(String[] arr, String targetValue) {  
            int a = Arrays.binarySearch(arr, targetValue);
            return a > 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

为了进行测试,我进行了一项测试,比较了 3 条关于速度的建议。我生成了随机整数,将其转换为字符串并将其添加到数组中。然后,我搜索可能的最大数字 / 字符串,这对于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);
}

您可以使用Arrays 类对值执行二进制搜索。如果未对数组进行排序,则必须使用同一类中的 sort 函数对数组进行排序,然后对其进行搜索。