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

How do I determine whether an array contains a particular value in Java?

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

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

考虑到String s,有没有一个很好的方法来测试VALUES是否含有s


1
Arrays.asList(yourArray).contains(yourValue)

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

从Java-8开始,您现在可以使用流。

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

为了检查intdoublelong的数组是否包含值,请分别使用IntStreamDoubleStreamLongStream

例子

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


先清除代码。我们已经(更正):

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

这是一个可变的静态,findbugs会告诉你是非常淘气。它应该是私有的:

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

(注意,您实际上可以删除new String[];位。)

所以,引用数组是坏的,特别是在这里我们需要一个集合:

1
2
3
private static final Set<String> VALUES = new HashSet<String>(Arrays.asList(
     new String[] {"AB","BC","CD","AE"}
));

(像我这样偏执的人,如果把它包在Collections.unmodifiableSet里,可能会感到更自在,甚至可以公开。)

"对于给定的字符串s,是否有一种测试值是否包含s的好方法?"

1
VALUES.contains(s)

O(1)。

更新:自Java SE 9以来,我们拥有EDCOX1×8。

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

正确的类型,不可变,O(1)和简洁。美丽的。

(更详细地说,CollectionsAPI仍然缺少不变的集合类型,而且语法对我来说仍然太冗长了。)


你可以使用ApacheCommonsLang的ArrayUtils.contains

public static boolean contains(Object[] array, Object objectToFind)

注意,如果传递的数组是null,则此方法返回false

还有一些方法可用于各种基元数组。

例子:

1
2
3
4
5
String[] fieldsToInclude = {"id","name","location" };

if ( ArrayUtils.contains( fieldsToInclude,"id" ) ) {
    // Do some stuff.
}


只需手动执行即可:

1
2
3
4
5
6
7
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()方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
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。

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

一般来说,如果您要进行大量的成员资格检查,您可能希望将所有内容存储在一个集合中,而不是数组中。


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

1)使用列表:

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

2)使用集合:

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

3)使用简单的循环:

1
2
3
4
5
6
7
public static boolean useLoop(String[] arr, String targetValue) {
    for (String s: arr) {
        if (s.equals(targetValue))
            return true;
    }
    return false;
}

4)使用array.binarysearch():

下面的代码是错误的,为了完整起见,这里列出了它。BinarySearch()只能用于已排序的数组。你会发现下面的结果很奇怪。这是对数组排序时的最佳选项。

1
2
3
4
public static boolean binarySearch(String[] arr, String targetValue) {  
            int a = Arrays.binarySearch(arr, targetValue);
            return a > 0;
        }

快速实例:

1
2
3
4
5
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()来说是最坏的情况。

使用10 k数组大小时,结果是:

1
2
3
Sort & Search   : 15
Binary Search   : 0
asList.contains : 0

使用100K数组时,结果是:

1
2
3
Sort & Search   : 156
Binary Search   : 0
asList.contains : 32

因此,如果数组是按排序顺序创建的,那么二进制搜索是最快的,否则asList().contains将是最快的方法。如果您有许多搜索,那么对数组进行排序以便使用二进制搜索可能是值得的。这完全取决于您的应用程序。

我想这是大多数人所期望的结果。测试代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
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));
    }
}


使用Java 8可以创建流并检查流中的任何条目是否匹配EDCOX1 OR 12:

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

或作为通用方法:

1
2
3
public static <T> boolean arrayContains(T[] array, T value) {
    return Arrays.stream(array).anyMatch(value::equals);
}


您可以使用array.as list方法直接将其初始化为列表,而不是使用快速数组初始化语法,例如:

1
public static final List<String> STRINGS = Arrays.asList("firstString","secondString" ....,"lastString");

然后你可以这样做(如上所述):

1
STRINGS.contains("the string you want to find");


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


顽固分子(但我认为在这里有个教训):

1
2
3
4
5
6
7
8
9
10
enum Values {
    AB, BC, CD, AE
}

try {
    Values.valueOf(s);
    return true;
} catch (IllegalArgumentException exc) {
    return false;
}


实际上,如果按照Tom Hawtin的建议使用hashset,则无需担心排序问题,而且您的速度与预排序数组上的二进制搜索速度相同,甚至可能更快。

显然,这完全取决于代码的设置方式,但从我的立场来看,顺序是:

在未排序的数组上:

  • 哈希表
  • 阿斯利特
  • 排序和二进制
  • 在已排序的数组上:

  • 哈希表
  • 二元的
  • 阿斯利特
  • 所以不管怎样,都是为了胜利。


    如果你有google收藏库,Tom的答案可以通过使用不可变集(http://google-collections.googlecode.com/svn/trunk/javadoc/com/google/common/collect/immutableset.html)简化很多。

    这确实从提议的初始化中消除了很多混乱。

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

    一种可能的解决方案:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    import java.util.Arrays;
    import java.util.List;

    public class ArrayContainsElement {
      public static final List<String> VALUES = Arrays.asList("AB","BC","CD","AE");

      public static void main(String args[]) {

          if (VALUES.contains("AB")) {
              System.out.println("Contains");
          } else {
              System.out.println("Not contains");
          }
      }
    }


    开发人员经常这样做:

    1
    2
    Set<String> set = new HashSet<String>(Arrays.asList(arr));
    return set.contains(targetValue);

    上面的代码可以工作,但不需要先将列表转换为set。将列表转换为集合需要额外的时间。它可以简单到:

    1
    Arrays.asList(arr).contains(targetValue);

    1
    2
    3
    4
    5
    6
       for(String s: arr){
            if(s.equals(targetValue))
                return true;
        }

    return false;

    第一个比第二个更可读。


    在Java 8中使用流。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    List<String> myList =
    Arrays.asList("a1","a2","b1","c2","c1");

    myList
    .stream()
    .filter(s -> s.startsWith("c"))
    .map(String::toUpperCase)
    .sorted()
    .forEach(System.out::println);


    使用简单的循环是最有效的方法。

    1
    2
    3
    4
    5
    6
    7
    boolean useLoop(String[] arr, String targetValue) {
        for(String s: arr){
            if(s.equals(targetValue))
                return true;
        }
        return false;
    }

    向ProgramCreek致意


  • 对于有限长度的阵列,请使用以下内容(如Camickr提供的)。重复检查的速度很慢,特别是对于较长的数组(线性搜索)。

    1
     Arrays.asList(...).contains(...)
  • 如果您重复检查一组较大的元素,则可以获得快速性能

    • 数组的结构不正确。使用TreeSet并将每个元素添加到其中。它对元素进行排序,并具有快速的exist()方法(二进制搜索)。

    • 如果元素实现了Comparable和,您希望TreeSet相应排序:

      ElementClass.compareTo()方法必须与ElementClass.equals()兼容:看三合会没有出现打架?(Java设置缺少一个项)

      1
      2
      3
      4
      5
      6
      7
      TreeSet myElements = new TreeSet();

      // Do this for each element (implementing *Comparable*)
      myElements.add(nextElement);

      // *Alternatively*, if an array is forceably provided from other code:
      myElements.addAll(Arrays.asList(myArray));
    • 否则,请使用您自己的Comparator

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      class MyComparator implements Comparator<ElementClass> {
           int compareTo(ElementClass element1; ElementClass element2) {
                // Your comparison of elements
                // Should be consistent with object equality
           }

           boolean equals(Object otherComparator) {
                // Your equality of comparators
           }
      }


      // construct TreeSet with the comparator
      TreeSet myElements = new TreeSet(new MyComparator());

      // Do this for each element (implementing *Comparable*)
      myElements.add(nextElement);
    • 回报:检查某些元素的存在:

      1
      2
      // Fast binary search through sorted elements (performance ~ log(size)):
      boolean containsElement = myElements.exists(someElement);

  • 试试这个:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    ArrayList<Integer> arrlist = new ArrayList<Integer>(8);

    // use add() method to add elements in the list
    arrlist.add(20);
    arrlist.add(25);
    arrlist.add(10);
    arrlist.add(15);

    boolean retval = arrlist.contains(10);
    if (retval == true) {
        System.out.println("10 is contained in the list");
    }
    else {
        System.out.println("10 is not contained in the list");
    }


    使用以下方法(本代码中的contains()方法为ArrayUtils.in()):

    对象实用程序.java

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    public class ObjectUtils{

        /**
         * A null safe method to detect if two objects are equal.
         * @param object1
         * @param object2
         * @return true if either both objects are null, or equal, else returns false.
         */

        public static boolean equals(Object object1, Object object2){
            return object1==null ? object2==null : object1.equals(object2);
        }

    }

    Java语言

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    public class ArrayUtils{

        /**
         * Find the index of of an object is in given array, starting from given inclusive index.
         * @param ts  Array to be searched in.
         * @param t  Object to be searched.
         * @param start  The index from where the search must start.
         * @return Index of the given object in the array if it is there, else -1.
         */

        public static <T> int indexOf(final T[] ts, final T t, int start){
            for(int i = start; i < ts.length; ++i)
                if(ObjectUtils.equals(ts[i], t))
                    return i;
            return -1;
        }

        /**
         * Find the index of of an object is in given array, starting from 0;
         * @param ts  Array to be searched in.
         * @param t  Object to be searched.
         * @return  indexOf(ts, t, 0)
         */

        public static <T> int indexOf(final T[] ts, final T t){
            return indexOf(ts, t, 0);
        }

        /**
         * Detect if the given object is in the given array.
         * @param ts  Array to be searched in.
         * @param t  Object to be searched.
         * @return  If indexOf(ts, t) is greater than -1.
         */

        public static <T> boolean in(final T[] ts, final T t){
            return indexOf(ts, t) > -1 ;
        }

    }

    正如您在上面的代码中看到的,在其他地方也使用了其他实用方法ObjectUtils.equals()ArrayUtils.indexOf()


    如果你不想让它区分大小写

    1
    Arrays.stream(VALUES).anyMatch(s::equalsIgnoreCase);

    检查这个

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    String[] VALUES = new String[] {"AB","BC","CD","AE"};
    String s;

    for(int i=0; i< VALUES.length ; i++)
    {
        if ( VALUES[i].equals(s) )
        {
            // do your stuff
        }
        else{    
            //do your stuff
        }
    }


    arrays.aslist()->然后调用contains()方法将始终有效,但是搜索算法要好得多,因为您不需要在数组周围创建轻量级的列表包装器,这就是arrays.aslist()所做的。

    1
    2
    3
    4
    5
    6
    7
    8
    public boolean findString(String[] strings, String desired){
       for (String str : strings){
           if (desired.equals(str)) {
               return true;
           }
       }
       return false; //if we get here… there is no desired String, return false.
    }


    是否使用Array.BinarySearch(array,obj)在数组中查找给定对象。

    例子:

    1
    if (Array.BinarySearch(str, i) > -1)` → true --exists

    假--不存在


    创建一个最初设置为假的布尔值。运行一个循环来检查数组中的每个值,并与要检查的值进行比较。如果有匹配,请将Boolean设置为true并停止循环。然后断言布尔值为真。