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

Mik*_*ler 2194 java arrays

我有一个String[]像这样的值:

public static final String[] VALUES = new String[] {"AB","BC","CD","AE"};
Run Code Online (Sandbox Code Playgroud)

鉴于String s,有没有一种好的方法来测试是否VALUES包含s

cam*_*ckr 2828

Arrays.asList(yourArray).contains(yourValue)
Run Code Online (Sandbox Code Playgroud)

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


您现在可以使用Streams.

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

要检查的阵列是否int,doublelong包含一个值使用IntStream,DoubleStreamLongStream分别.

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

  • 你不会失去太多,因为asList()返回一个ArrayList,它的核心是一个数组.构造函数只会更改一个引用,因此在那里做的工作量不大.而contains()/ indexOf()将迭代并使用equals().但是对于原语,你最好自己编码.对于字符串或其他类,差异不会明显. (185认同)
  • 我对Arrays类中的搜索函数与迭代数组和使用equals()函数或==表示基元的性能有点好奇. (85认同)
  • Nyerguds:事实上,这对原始人不起作用.在java原始类型中不能是通用的.asList声明为<T> List <T> asList(T ...).当你将int []传递给它时,编译器会推断T = int [],因为它不能推断T = int,因为基元不能是通用的. (61认同)
  • @Joey只是旁注,它是一个`ArrayList`,但不是你想要的`java.util.ArrayList`,返回的真正类是:`java.util.Arrays.ArrayList <E>`定义为:`public class java.util.Arrays {private static class ArrayList <E> ... {}}`. (28认同)
  • 奇怪的是,NetBeans声称'int [] holidays'的'Arrays.asList(holidays)'返回'list <int []>',而不是'list <int>'.它只包含一个元素.意味着Contains不起作用,因为它只有一个元素; int数组. (18认同)
  • @Јοеу因为它不是"普通"的ArrayList,[Arrays.asList(T ...)](http://docs.oracle.com/javase/6/docs/api/java/util/Arrays.html# asList%28T ...%29)"返回由指定数组支持的固定大小的列表." Arrays.ArrayList只是现有数组的"瘦"List-wrapper.最重要的是,您无法添加或删除元素,因为它不会分配自己的数组,而是直接使用原始数据.这使得它的使用非常便宜,因为不需要进行复制,它只存储对原始数组的引用.所以不要害怕使用Arrays.asList(T ...),它并不昂贵. (11认同)
  • 它们都是线性搜索. (3认同)
  • 该方法比搜索循环的基本慢约3倍 (2认同)
  • @Loc,完全同意,我质疑2年前它有75的所有票数.任何答案都应该有10个限制.答案不应该用于人气竞赛,只是表明这是OP应该考虑解决给定问题的答案. (2认同)
  • upvotes有什么问题?它节省了一些人的时间,更好奇的阅读评论和了解更多,从而在未来做出更好的决策.对我来说,这是一个成功的答案. (2认同)
  • @ tgm1024:正如其他人在你上面的评论中解释的那样,这只是一个不做任何复制的薄包装器.http://stackoverflow.com/questions/1128723/how-can-i-test-if-an-array-contains-a-certain-value#comment25845601_1128728 (2认同)

Tom*_*ine 346

只是为了开始清除代码.我们已经(更正):

public static final String[] VALUES = new String[] {"AB","BC","CD","AE"};
Run Code Online (Sandbox Code Playgroud)

这是一个可变的静态,FindBugs会告诉你这是非常顽皮的.它应该是私人的:

private static final String[] VALUES = new String[] {"AB","BC","CD","AE"};
Run Code Online (Sandbox Code Playgroud)

(注意,你实际上可以放弃这new String[];一点.)

所以,参考数组很糟糕,特别是在这里我们需要一个集合:

private static final Set<String> VALUES = new HashSet<String>(Arrays.asList(
     new String[] {"AB","BC","CD","AE"}
));
Run Code Online (Sandbox Code Playgroud)

(偏执狂的人,比如我自己,如果被包裹起来,可能会感到更放心Collections.unmodifiableSet- 甚至可以公之于众.)

"鉴于String,有没有一种很好的方法来测试VALUES是否包含s?"

VALUES.contains(s)
Run Code Online (Sandbox Code Playgroud)

O(1).

  • 除了它是O(N)首先创建集合:) (178认同)
  • 如果它是静态的,它可能会被使用很多次.因此,与大量线性搜索的成本相比,初始化该集合所花费的时间很可能非常小. (58认同)
  • @nmr一个`TreeSet`将是'O(log n)`.`HashSet的缩放使得桶中元素的平均数大致不变.至少对于最多2 ^ 30的阵列.例如,大O分析忽略的硬件缓存可能会产生影响.还假设散列函数有效地工作. (6认同)
  • @TomHawtin-tackline 为什么你说“特别是我们想要一套”?在这种情况下 Set (HashSet) 的优势是什么?为什么“引用数组”不好(“引用数组”是指由调用 `Arrays.asList` 生成的数组支持的 ArrayList)? (2认同)
  • 这并没有回答有关数组的问题。你只是说“不要使用数组”,这不是解决方案。此外,你只是说“X 不好”,但没有解释为什么这对答案总是不好。 (2认同)
  • 至少在 OpenJDK 实现中,四参数 Set.of 方法不会返回 HashSet 数据结构;对于这么少的元素,这效率不高。请参阅此处的代码:http://hg.openjdk.java.net/jdk9/jdk9/jdk/file/86f19074aad2/src/java.base/share/classes/java/util/ImmutableCollections.java#l309 (2认同)

Int*_*cer 195

您可以使用ArrayUtils.containsApache的百科全书郎

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

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

还有适用于各种原始数组的方法.

例:

String[] fieldsToInclude = { "id", "name", "location" };

if ( ArrayUtils.contains( fieldsToInclude, "id" ) ) {
    // Do some stuff.
}
Run Code Online (Sandbox Code Playgroud)

  • 用于78kb android应用程序的300kb库,并不总是好的 (111认同)
  • @ max4ever有时你已经包含了这个库(出于其他原因),这是一个非常有效的答案.我一直在寻找这个,我已经依赖于Apache Commons Lang.谢谢你的回答. (37认同)
  • @ max4ever大多数Android应用程序都被Proguard最小化,只将您需要的类和功能放入您的应用程序中.这使得它等于自己滚动,或者复制apache的源代码.谁不使用该最小化不需要抱怨700kb或78kb :) (10认同)
  • @ max4ever我同意,但这仍然比"滚动你自己"更好,更容易阅读原始的java方式. (4认同)
  • 包:[org.apache.commons.lang.ArrayUtils](http://commons.apache.org/proper/commons-lang/javadocs/api-2.6/org/apache/commons/lang/ArrayUtils.html) (2认同)

icz*_*cza 156

只需简单地手工实现:

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;
}
Run Code Online (Sandbox Code Playgroud)

改进:

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;
}
Run Code Online (Sandbox Code Playgroud)

  • 为什么这个函数不是Java的一部分?难怪有人说Java是臃肿的...看看上面的所有答案,当你需要的是for循环时,使用一堆库.这些天孩子们! (20认同)
  • @icza如果你看一下'Arrays`和`ArrayList`的来源,结果证明这不一定比使用`Arrays.asList(...).contains(...)`的版本更快.创建`ArrayList`的开销非常小,`ArrayList.contains()`使用比上面显示的更智能的循环(实际上它使用两个不同的循环)(JDK 7). (11认同)
  • @AlastorMoody e == v做一个非常快的参考相等检查.如果相同的对象(通过引用相同)在数组中,则会更快找到它.如果它不是同一个实例,它仍然可能与equals()方法声明的相同,如果引用不相同,则检查此内容. (10认同)
  • @Phoexo这个解决方案显然更快,因为接受的答案将数组包装到一个列表中,并调用该列表上的contains()方法,而我的解决方案基本上只执行contains(). (9认同)
  • @phreakhead它是Java的一部分,参见`Collection.contains(Object)` (4认同)
  • @deworde我有点不同意.如果您需要有关contains操作的性能,请不要使用数组(而是[HashSet](https://docs.oracle.com/javase/8/docs/api/java/util/HashSet.html)) .问题是关于数组,所以我展示了如何使用数组.第一个解决方案只是一个简单的循环,它根本不复杂.而且,如果已经给出了一个数组,并且您很少或根本没有选择数据结构的选择,那么改进的版本确实有价值. (4认同)
  • 另见:马铃薯编程. (2认同)
  • https://en.wikipedia.org/wiki/Loop-invariant_code_motion “改进”是没有用的,任何合理的编译器(包括 HotSpot 中的 C1 和 C2)都会将 null 检查移到循环之外,因为参数是最终的并且无法更改。 (2认同)

Uri*_*Uri 71

如果数组未排序,则必须迭代所有内容并在每个上调用equals.

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

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


Sir*_*dda 69

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

1)使用List:

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

2)使用Set:

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

3)使用简单的循环:

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

4)使用Arrays.binarySearch():

下面的代码是错误的,这里列出的是完整性.binarySearch()只能用于排序数组.你会发现下面的结果很奇怪.这是排序数组时的最佳选择.

public static boolean binarySearch(String[] arr, String targetValue) {  
            int a = Arrays.binarySearch(arr, targetValue);
            return a > 0;
        }
Run Code Online (Sandbox Code Playgroud)

快速示例:

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
Run Code Online (Sandbox Code Playgroud)

  • 为什么?我认为它应该返回> -1,因为0表示它包含在数组的头部. (6认同)
  • 你的二进制搜索示例应该返回> 0; (5认同)
  • `(a &gt;= 0)` 的第一个变体是正确的,只需检查 [the docs](https://docs.oracle.com/javase/8/docs/api/java/util/Arrays.html#binarySearch- int:A-int-),他们说“请注意,这保证当且仅当找到键时返回值将 &gt;= 0”。 (2认同)

cam*_*ckr 49

为了它的价值,我进行了一项测试,比较了3个速度建议.我生成了随机整数,将它们转换为String并将它们添加到数组中.然后我搜索了最高可能的数字/字符串,这对于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));
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 此测试存在缺陷,因为它在**相同的**JVM实例中运行所有3个测试.后面的测试可以从早期的热身,JIT等热身中获益 (7认同)
  • 我不明白这段代码.您对数组'strings'进行排序,并在对binarySearch的两次调用中使用相同(已排序)的数组.除了HotSpot运行时优化之外,它如何显示任何内容?与asList.contains调用相同.您从已排序的数组创建一个列表,然后在其上包含具有最高值的列表.当然这需要时间.这个测试的意义是什么?更不用说是一个不正确编写的微基准 (6认同)
  • 这个测试实际上完全不相关.排序和搜索是线性(n*log(n))复杂度,二进制搜索是对数的,而ArrayUtils.contains显然是线性的.将这些解决方案进行比较是没有用的,因为它们处于完全不同的复杂性类别中. (4认同)

Mar*_*des 37

您也可以使用Arrays.asList方法以类似的方式直接将其初始化为List,而不是使用快速数组初始化语法,例如:

public static final List<String> STRINGS = Arrays.asList("firstString", "secondString" ...., "lastString");
Run Code Online (Sandbox Code Playgroud)

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

STRINGS.contains("the string you want to find");
Run Code Online (Sandbox Code Playgroud)


ass*_*ias 35

使用Java 8,您可以创建流并检查流中的任何条目是否匹配"s":

String[] values = {"AB","BC","CD","AE"};
boolean sInArray = Arrays.stream(values).anyMatch("s"::equals);
Run Code Online (Sandbox Code Playgroud)

或者作为通用方法:

public static <T> boolean arrayContains(T[] array, T value) {
    return Arrays.stream(array).anyMatch(value::equals);
}
Run Code Online (Sandbox Code Playgroud)

  • 值得注意原始专业化. (3认同)

Tho*_*ens 28

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


Tom*_*ine 18

ObStupidAnswer(但我认为这里有一个教训):

enum Values {
    AB, BC, CD, AE
}

try {
    Values.valueOf(s);
    return true;
} catch (IllegalArgumentException exc) {
    return false;
}
Run Code Online (Sandbox Code Playgroud)

  • 异常抛出显然很重,但这将是一种测试值(如果有效)的新颖方法。缺点是必须事先定义枚举。 (2认同)

小智 13

实际上,如果您使用HashSet <String>,因为Tom Hawtin建议您不必担心排序,并且您的速度与预先排序的数组上的二进制搜索相同,可能更快.

这一切都取决于您的代码的设置方式,显然,但从我的立场来看,订单将是:

未排序的数组上:

  1. HashSet的
  2. asList
  3. 排序和二进制

在排序的数组上:

  1. HashSet的
  2. 二进制
  3. asList

无论哪种方式,HashSet为胜利.

  • HashSet成员资格应为O(1),并且对已排序集合的二进制搜索为O(log n). (2认同)

jho*_*ges 11

如果你有谷歌馆藏库,可以通过使用ImmutableSet(http://google-collections.googlecode.com/svn/trunk/javadoc/com/google/common/collect/ImmutableSet.html)简化汤姆的答案.

这确实消除了所提出的初始化中的大量混乱

private static final Set<String> VALUES =  ImmutableSet.of("AB","BC","CD","AE");
Run Code Online (Sandbox Code Playgroud)


小智 10

一种可能的方案:

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");
      }
  }
}
Run Code Online (Sandbox Code Playgroud)


Xar*_*mer 8

开发人员经常这样做:

Set<String> set = new HashSet<String>(Arrays.asList(arr));
return set.contains(targetValue);
Run Code Online (Sandbox Code Playgroud)

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

Arrays.asList(arr).contains(targetValue);
Run Code Online (Sandbox Code Playgroud)

要么

   for(String s: arr){
        if(s.equals(targetValue))
            return true;
    }

return false;
Run Code Online (Sandbox Code Playgroud)

第一个比第二个更可读.


Rya*_*yan 7

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

boolean useLoop(String[] arr, String targetValue) {
    for(String s: arr){
        if(s.equals(targetValue))
            return true;
    }
    return false;
}
Run Code Online (Sandbox Code Playgroud)

Programcreek提供


小智 7

Java 8中使用Streams.

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);
Run Code Online (Sandbox Code Playgroud)

  • 这种方法有什么优势吗? (7认同)

Kap*_*lan 6

自 Java 9 以来
数组 VALUES 可能包含重复项的最短解决方案

List.of(VALUES).contains(s);
Run Code Online (Sandbox Code Playgroud)


Gle*_*est 5

  1. 对于有限长度的数组,请使用以下内容(由camickr给出)。对于重复检查,这很慢,特别是对于较长的数组(线性搜索)而言。

     Arrays.asList(...).contains(...)
    
    Run Code Online (Sandbox Code Playgroud)
  2. 为了提高性能,如果您反复检查较大的一组元素

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

    • 如果元素实现Comparable&您想要相应地TreeSet排序:

      ElementClass.compareTo()方法必须与兼容ElementClass.equals():请参阅三合会未露面打架?(Java Set缺少项目)

      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));
      
      Run Code Online (Sandbox Code Playgroud)
    • 否则,请使用您自己的Comparator

      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);
      
      Run Code Online (Sandbox Code Playgroud)
    • 回报:检查某些元素的存在:

      // Fast binary search through sorted elements (performance ~ log(size)):
      boolean containsElement = myElements.exists(someElement);
      
      Run Code Online (Sandbox Code Playgroud)

  • 为什么要打扰`TreeSet`?HashSet`更快(O(1)),不需要订购。 (4认同)

Abh*_*Oza 5

使用以下内容(contains()方法ArrayUtils.in()在此代码中):

ObjectUtils.java

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);
    }
}
Run Code Online (Sandbox Code Playgroud)

ArrayUtils.java

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;
    }
}
Run Code Online (Sandbox Code Playgroud)

正如您在上面的代码中看到的那样,还有其他实用方法ObjectUtils.equals()ArrayUtils.indexOf(),它们也在其他地方使用过。


小智 5

如果你不希望它区分大小写

Arrays.stream(VALUES).anyMatch(s::equalsIgnoreCase);
Run Code Online (Sandbox Code Playgroud)


小智 5

使用下面 -

    String[] values = {"AB","BC","CD","AE"};
    String s = "A";
    boolean contains = Arrays.stream(values).anyMatch(v -> v.contains(s));
Run Code Online (Sandbox Code Playgroud)