我有一个具有如下值的 String[]
:
public static final String[] VALUES = new String[] {"AB","BC","CD","AE"};
给定 String s
,是否有测试 VALUES
是否包含 s
的好方法?
java.util.Arrays
中的简单 indexOf
和 contains
- 它们都包含简单的循环。是的,你可以在 1 分钟内写完这些;但我仍然去了 StackOverflow 期望在 JDK 的某个地方找到它们。
Arrays.asList(yourArray).contains(yourValue)
警告:这不适用于基元数组(请参阅注释)。
从 java-8 开始,您现在可以使用 Streams。
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);
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 仍然缺少不可变集合类型,而且语法仍然过于冗长,不符合我的口味。)
Arrays.asList
生成的数组支持的 ArrayList)?
TreeSet
将是 O(log n)
。 HashSet
被缩放,使得桶中元素的平均数量大致恒定。至少对于最多 2^30 的数组。例如,可能会受到 big-O 分析忽略的硬件缓存的影响。还假设哈希函数有效工作。
您可以使用 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)
Arrays
和 ArrayList
的来源,事实证明这不一定比使用 Arrays.asList(...).contains(...)
的版本快。创建 ArrayList
的开销非常小,并且 ArrayList.contains()
使用比上面所示的循环(JDK 7)更智能的循环(实际上它使用两个不同的循环)。
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
快速示例:
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
(a >= 0)
的变体是正确的,只需检查 the docs,他们说“请注意,这保证了当且仅当找到密钥时返回值将是 >= 0”。
如果数组未排序,则必须遍历所有内容并在每个上调用 equals。
如果数组已排序,则可以进行二分搜索,Arrays 类中有一个。
一般来说,如果您要进行大量的成员资格检查,您可能希望将所有内容存储在 Set 中,而不是存储在数组中。
对于它的价值,我进行了一个测试,比较了 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);
}
anyMatch
JavaDoc 声明它是 "...May not evaluate the predicate on all elements if not necessary for determining the result."
,因此它可能不需要在找到匹配项后继续处理。
您可以使用 Arrays class 对值执行二分搜索。如果您的数组未排序,则必须使用同一类中的排序函数对数组进行排序,然后搜索它。
ObStupidAnswer(但我认为这里有一个教训):
enum Values {
AB, BC, CD, AE
}
try {
Values.valueOf(s);
return true;
} catch (IllegalArgumentException exc) {
return false;
}
实际上,如果您按照 Tom Hawtin 的建议使用 HashSet
显然,这完全取决于您的代码的设置方式,但是从我的立场来看,顺序是:
在未排序的数组上:
HashSet asList 排序和二进制
在排序数组上:
HashSet 二进制 asList
所以无论哪种方式,HashSet 都是赢家。
如果你有谷歌收藏库,汤姆的答案可以通过使用 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");
一种可能的解决方案:
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");
}
}
}
开发人员经常这样做:
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;
第一个比第二个更具可读性。
在 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);
使用简单的循环是最有效的方法。
boolean useLoop(String[] arr, String targetValue) {
for(String s: arr){
if(s.equals(targetValue))
return true;
}
return false;
}
使用以下代码(此代码中的 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()
,它们也在其他地方使用过。
对于长度有限的数组,请使用以下内容(由 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
TreeSet
? HashSet
更快 (O(1)) 并且不需要排序。
尝试这个:
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");
}
如果您不希望它区分大小写
Arrays.stream(VALUES).anyMatch(s::equalsIgnoreCase);
检查这个
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”)。
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.
}
最短的解决方案
数组 VALUES
可能包含重复项
自 Java 9 起
List.of(VALUES).contains(s);
使用 Array.BinarySearch(array,obj)
在数组中查找给定对象。
例子:
if (Array.BinarySearch(str, i) > -1)` → true --exists
false -- 不存在
Array.BinarySearch
和 Array.FindIndex
是 .NET 方法,在 Java 中不存在。
The array must be sorted prior to making this call. If it is not sorted, the results are undefined.
尝试使用 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
创建一个初始设置为 false 的布尔值。运行一个循环来检查数组中的每个值并与您要检查的值进行比较。如果您遇到匹配,请将 boolean 设置为 true 并停止循环。然后断言布尔值是真的。
当我使用原始类型 byte 和 byte[] 处理低级 Java 时,到目前为止我得到的最好的是来自 bytes-java https://github.com/patrickfav/bytes-java 似乎是一项不错的工作
您可以通过两种方法检查它
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));
}
ArrayList
,但不是您期望的java.util.ArrayList
,真正返回的类是:java.util.Arrays.ArrayList<E>
定义为:public class java.util.Arrays {private static class ArrayList<E> ... {}}
。