ChatGPT解决这个技术问题 Extra ChatGPT

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

我有一个具有如下值的 String[]

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

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

很长的路要走,但是您可以使用 for 循环:“for (String s : VALUES) if (s.equals("MYVALUE")) return true;
@camickr--我的情况几乎与此相同:stackoverflow.com/a/223929/12943 它只是不断获得选票,但只是 sun 文档的复制/粘贴。我猜分数是基于你提供了多少帮助,而不是你付出了多少努力——主要是你发布它的速度!也许我们偶然发现了约翰斯基特的秘密!很好的答案,为你+1。
如果您使用的是 Apache Commons,那么 org.apache.commons.lang.ArrayUtils.contains() 会为您执行此操作。
@camickr 因为像我这样的人在谷歌上搜索一个问题,点击 SO 结果,查看你的答案,测试它,它有效,投票给答案,然后离开。
我真的很怀念 java.util.Arrays 中的简单 indexOfcontains - 它们都包含简单的循环。是的,你可以在 1 分钟内写完这些;但我仍然去了 StackOverflow 期望在 JDK 的某个地方找到它们。

R
Ray Hulha
Arrays.asList(yourArray).contains(yourValue)

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

从 java-8 开始,您现在可以使用 Streams。

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

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

例子

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

我有点好奇 this 与 Arrays 类中的搜索函数与迭代数组并使用 equals() 函数或 == 用于基元的性能。
你不会损失太多,因为 asList() 返回一个 ArrayList,它的核心是一个数组。构造函数只会改变一个引用,所以在那里不需要做太多的工作。并且 contains()/indexOf() 将迭代并使用 equals()。不过,对于原语,您最好自己编写代码。对于字符串或其他类,差异不会很明显。
奇怪的是,NetBeans 声称“int[] 假期”的“Arrays.asList(holidays)”返回一个“list”,而不是“list”。它只包含一个元素。这意味着 Contains 不起作用,因为它只有一个元素;整数数组。
Nyerguds:确实,这不适用于原语。在 java 中,原始类型不能是泛型的。 asList 被声明为 List asList(T...)。当您将 int[] 传递给它时,编译器会推断 T=int[] 因为它不能推断 T=int,因为原语不能是通用的。
@Joey 只是一个旁注,它是一个 ArrayList,但不是您期望的 java.util.ArrayList,真正返回的类是:java.util.Arrays.ArrayList<E> 定义为:public class java.util.Arrays {private static class ArrayList<E> ... {}}
C
Community

Java SE 9 的简明更新

参考数组不好。对于这种情况,我们是在一组之后。从 Java SE 9 开始,我们有了 Set.of

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

“给定 String s,有没有一种测试 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 中,可能会感到更自在——甚至可以将其公开。)

(*关于品牌的更多信息,可以预见,集合 API 仍然缺少不可变集合类型,而且语法仍然过于冗长,不符合我的口味。)


除了首先创建集合是 O(N) :)
如果它是静态的,它可能会被使用很多次。因此,与大量线性搜索的成本相比,初始化集合所花费的时间很有可能非常小。
@TomHawtin-tackline 你为什么说“特别是在这里我们想要一套”?在这种情况下,Set(HashSet)有什么优势?为什么“参考数组”不好(“参考数组”是指由调用 Arrays.asList 生成的数组支持的 ArrayList)?
@nmr A TreeSet 将是 O(log n)HashSet 被缩放,使得桶中元素的平均数量大致恒定。至少对于最多 2^30 的数组。例如,可能会受到 big-O 分析忽略的硬件缓存的影响。还假设哈希函数有效工作。
这并不能回答有关数组的问题。您只是说“不要使用数组”,这不是解决方案。此外,您只是说“X 不好”,但没有解释为什么这对答案总是不好的。
I
Intracer

您可以使用 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.
}

@max4ever 我同意,但这仍然比“滚动你自己的”更好,并且比原始的 Java 方式更容易阅读。
@max4ever 有时您已经包含了这个库(出于其他原因),这是一个完全有效的答案。我一直在寻找这个,我已经依赖于 Apache Commons Lang。感谢您的回答。
或者您可以只复制该方法(以及如果有的话)。
@max4ever 大多数 android 应用程序都被 Proguard 最小化,只将你需要的类和函数放入你的应用程序中。这使它等于滚动您自己的,或复制 apache 事物的源代码。任何不使用最小化的人都不需要抱怨 700kb 或 78kb :)
P
Peter Mortensen

只需简单地手动实现它:

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;
}

@Phoexo这个解决方案显然更快,因为接受的答案将数组包装成一个列表,并在该列表上调用 contains() 方法,而我的解决方案基本上只做 contains() 会做的事情。
@AlastorMoody e==v 进行非常快的引用相等检查。如果相同的对象(通过引用相同)在数组中,将更快地找到它。如果不是同一个实例,它仍然可能与 equals() 方法声明的相同,如果引用不同,则检查此内容。
为什么这个函数不是 Java 的一部分?难怪人们说 Java 太臃肿了……看看上面的所有答案,当你只需要一个 for 循环时,它们使用了一堆库。现在的孩子们!
@phreakhead 它是 Java 的一部分,请参阅 Collection.contains(Object)
@icza 如果您查看 ArraysArrayList 的来源,事实证明这不一定比使用 Arrays.asList(...).contains(...) 的版本快。创建 ArrayList 的开销非常小,并且 ArrayList.contains() 使用比上面所示的循环(JDK 7)更智能的循环(实际上它使用两个不同的循环)。
I
Ivar

Four Different Ways to Check If an Array Contains a Value

使用列表: public static boolean useList(String[] arr, String targetValue) { return Arrays.asList(arr).contains(targetValue); } 使用集合: public static boolean useSet(String[] arr, String targetValue) { Set set = new HashSet(Arrays.asList(arr));返回 set.contains(targetValue); } 使用一个简单的循环: public static boolean useLoop(String[] arr, String targetValue) { for (String s: arr) { if (s.equals(targetValue)) return true; } 返回假;使用 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

您的二进制搜索示例应返回 > 0;
为什么?我认为它应该返回 > -1,因为 0 表示它包含在数组的头部。
第一个带有 (a >= 0) 的变体是正确的,只需检查 the docs,他们说“请注意,这保证了当且仅当找到密钥时返回值将是 >= 0”。
为什么适用于 String 而不是 int? static boolean exists(int[] ints, int k) { return Arrays.asList(ints).contains(k); }
U
Uri

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

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

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


另外,就像我在回答中所说的那样,如果您使用 Arrays 类,您可以对数组进行排序,然后对新排序的数组执行二进制搜索。
@Thomas:我同意。或者您可以将所有内容添加到 TreeSet 中;相同的复杂性。如果它不改变,我会使用数组(也许可以节省一点内存位置,因为引用是连续定位的,尽管字符串不是)。如果这会随着时间的推移而改变,我会使用这套设备。
C
Community

对于它的价值,我进行了一个测试,比较了 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));
    }
}

我不明白这段代码。您对数组“字符串”进行排序,并在对 binarySearch 的两次调用中使用相同的(排序的)数组。除了 HotSpot 运行时优化之外,它还能显示什么?与 asList.contains 调用相同。您从排序后的数组创建一个列表,然后在其上包含最高值。当然,这需要时间。这个测试的意义是什么?更不用说编写不当的微基准测试了
此外,由于二分查找只能应用于已排序的集合,因此排序和搜索是使用二分查找的唯一可能方式。
由于许多其他原因,排序可能已经完成,例如,它可以在 init 上排序并且永远不会更改。可以单独测试搜索时间。然而,这失败的地方在于它是微基准测试的一个不太出色的例子。众所周知,微基准测试在 Java 中很难正确执行,例如应该包括在运行实际测试之前执行足以获得热点优化的测试代码,更不用说使用计时器运行实际测试代码超过一次。 Example pitfalls
该测试存在缺陷,因为它在同一个 JVM 实例中运行所有 3 个测试。后面的测试可以从早期的预热缓存、JIT 等中受益
这个测试实际上是完全无关的。排序和搜索是线性 (n*log(n)) 复杂度,二进制搜索是对数,ArrayUtils.contains 显然是线性的。比较这些解决方案是没有用的,因为它们属于完全不同的复杂性类别。
P
Peter Mortensen

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

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

然后你可以做(如上):

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

a
assylias

使用 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 声明它是 "...May not evaluate the predicate on all elements if not necessary for determining the result.",因此它可能不需要在找到匹配项后继续处理。
G
GKFX

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


您可以使用同一类中的排序函数来完成此操作...我应该将其添加到我的答案中。
我认为可能会比 asList().contains() 方法花费更多。除非您需要经常进行该检查(但如果它只是一个可以开始排序的静态值列表,公平地说)。
真的。关于哪个最有效,有很多变数。不过有选择也不错。
在此处执行此操作的一些代码:stackoverflow.com/a/48242328/9131078
为搜索目的对整个数组进行排序是昂贵的。我们可以为线性搜索本身使用相同的 CPU 时间。我更喜欢对预先按排序顺序构建的集合进行二进制搜索。
T
Tom Hawtin - tackline

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

enum Values {
    AB, BC, CD, AE
}

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

异常抛出显然很重,但如果它有效,这将是一种测试值的新颖方法。缺点是必须事先定义枚举。
P
Peter Mortensen

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

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

在未排序的数组上:

HashSet asList 排序和二进制

在排序数组上:

HashSet 二进制 asList

所以无论哪种方式,HashSet 都是赢家。


HashSet 成员资格应该是 O(1),并且对已排序集合的二进制搜索是 O(log n)。
j
jhodges

如果你有谷歌收藏库,汤姆的答案可以通过使用 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");

P
Pang

一种可能的解决方案:

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");
      }
  }
}

Z
Zar E Ahmer

开发人员经常这样做:

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

上面的代码有效,但无需先将列表转换为设置。将列表转换为集合需要额外的时间。它可以很简单:

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

或者

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

return false;

第一个比第二个更具可读性。


S
Shineed Basheer

在 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);

R
Ryan

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

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

致谢Programcreek


如果数组在目标值之前包含空引用,这将引发空指针异常。
if 语句应该是: if (targetValue.equals(s)) 因为 String equals 有一个 instanceof 检查器。
使用 Objects.equals(obj1,obj2) 代替为空安全。
A
Abhishek Oza

使用以下代码(此代码中的 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);
    }
}

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;
    }
}

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


C
Community

对于长度有限的数组,请使用以下内容(由 camickr 给出)。这对于重复检查来说很慢,尤其是对于较长的数组(线性搜索)。 Arrays.asList(...).contains(...) 如果您反复检查更大的元素集,为了提高性能 数组是错误的结构。使用 TreeSet 并向其中添加每个元素。它对元素进行排序并有一个快速的 exists() 方法(二分查找)。如果元素实现了 Comparable 并且您希望 TreeSet 相应地排序: ElementClass.compareTo() 方法必须与 ElementClass.equals() 兼容:请参阅 Triads 没有出现打架? (Java Set 缺少一项) TreeSet myElements = new TreeSet(); // 对每个元素执行此操作(实现 *Comparable*) myElements.add(nextElement); // *或者*,如果数组是从其他代码强制提供的:myElements.addAll(Arrays.asList(myArray));否则,使用您自己的比较器: class MyComparator implements Comparator { int compareTo(ElementClass element1; ElementClass element2) { // 你的元素比较 // 应该与对象相等性一致 } boolean equals(Object otherComparator) { // 你的比较器相等 } } // 用比较器构造 TreeSet TreeSet myElements = new TreeSet(new MyComparator()); // 对每个元素执行此操作(实现 *Comparable*) myElements.add(nextElement);回报:检查某些元素的存在://通过排序的元素进行快速二分搜索(性能 ~ log(size)):boolean containsElement = myElements.exists(someElement);


为什么要打扰 TreeSetHashSet 更快 (O(1)) 并且不需要排序。
P
Pang

尝试这个:

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");
}

A
Akhil Babu Korkandi

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

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

C
Community

检查这个

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
    }
}

这不起作用 - 它会为不匹配的 每个 项输入 else(因此,如果您要在该数组中查找“AB”,它将去那里 3 次,因为其中 3 个值不是“AB”)。
T
TheArchon

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

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.
}

K
Kaplan

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

List.of(VALUES).contains(s);

R
Ruslan

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

例子:

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

false -- 不存在


Array.BinarySearchArray.FindIndex 是 .NET 方法,在 Java 中不存在。
@ataylor java 中有 Arrays.binarySearch。但你是对的,没有 Arrays.findIndex
需要注意的是:The array must be sorted prior to making this call. If it is not sorted, the results are undefined.
V
Vipul Gulhane

尝试使用 Java 8 谓词测试方法

这是一个完整的例子。

import java.util.Arrays;
import java.util.List;
import java.util.function.Predicate;

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

    public static void main(String args[]) {
        Predicate<String> containsLetterA = VALUES -> VALUES.contains("AB");
        for (String i : VALUES) {
            System.out.println(containsLetterA.test(i));
        }
    }
}

http://mytechnologythought.blogspot.com/2019/10/java-8-predicate-test-method-example.html

https://github.com/VipulGulhane1/java8/blob/master/Test.java


m
mandy1339

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


t
truthadjustr

当我使用原始类型 byte 和 byte[] 处理低级 Java 时,到目前为止我得到的最好的是来自 bytes-java https://github.com/patrickfav/bytes-java 似乎是一项不错的工作


C
Community

您可以通过两种方法检查它

A) 通过将数组转换为字符串,然后通过.contains方法检查所需的字符串

String a = Arrays.toString(VALUES);
System.out.println(a.contains("AB"));
System.out.println(a.contains("BC"));
System.out.println(a.contains("CD"));
System.out.println(a.contains("AE"));

B)这是一种更有效的方法

Scanner s = new Scanner(System.in);

String u = s.next();
boolean d = true;
for (int i = 0; i < VAL.length; i++) {
    if (VAL[i].equals(u) == d)
        System.out.println(VAL[i] + " " + u + VAL[i].equals(u));
}

字符串转换效率低得离谱,解决方案也不正确,例如 contains(",") 将返回 true。