У меня есть String[]
с такими значениями:
public static final String[] VALUES = new String[] {"AB","BC","CD","AE"};
Учитывая String s
, есть ли хороший способ проверить, содержит ли VALUES
s
?
30 ответов
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);
ArrayList
, но не java.util.ArrayList
, как вы ожидали, реальный возвращаемый класс: java.util.Arrays.ArrayList<E>
определяется как: public class java.util.Arrays {private static class ArrayList<E> ... {}}
.
Просто реализуйте это вручную:
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).
Если массив не отсортирован, вам придется перебрать все и вызвать равенство для каждого.
Если массив отсортирован, вы можете выполнить двоичный поиск, он есть в Массивы.
Вообще говоря, если вы собираетесь проводить много проверок членства, вы можете хранить все в Set, а не в массиве.
Как бы то ни было, я провел тест, сравнивая 3 предложения по скорости. Я сгенерировал случайные целые числа, преобразовал их в строку и добавил в массив. Затем я поискал максимально возможное число / строку, что было бы наихудшим сценарием для asList().contains()
.
При использовании массива размером 10 КБ результаты были:
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));
}
}
Четыре разных способа проверить, содержит ли массив значение
Использование
List
:public static boolean useList(String[] arr, String targetValue) { return Arrays.asList(arr).contains(targetValue); }
Используя
Set
:public static boolean useSet(String[] arr, String targetValue) { Set<String> set = new HashSet<String>(Arrays.asList(arr)); return set.contains(targetValue); }
Используя простой цикл:
public static boolean useLoop(String[] arr, String targetValue) { for (String s: arr) { if (s.equals(targetValue)) return true; } return false; }
Использование
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
(a >= 0)
был правильным, просто проверьте документы, они говорят:« Обратите внимание, что это гарантирует, что возвращаемое значение будет> = 0, если и только если ключ найден ».
Вместо использования синтаксиса быстрой инициализации массива вы можете сразу же инициализировать его как List аналогичным образом, используя метод Arrays.asList, например:
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."
, поэтому, возможно, нет необходимости продолжать обработку после нахождения совпадения.
Для выполнения бинарный поиск значения. Если ваш массив не отсортирован, вам придется использовать функции сортировки в том же классе, чтобы отсортировать массив, а затем выполнить поиск по нему.
ObStupidAnswer (но я думаю, что здесь есть урок):
enum Values {
AB, BC, CD, AE
}
try {
Values.valueOf(s);
return true;
} catch (IllegalArgumentException exc) {
return false;
}
На самом деле, если вы используете HashSet
Все зависит от того, как настроен ваш код, очевидно, но с того места, где я стою, порядок будет следующим:
В несортированном массиве:
- HashSet
- asList
- сортировка и двоичный
В отсортированном массиве:
- HashSet
- Двоичный
- asList
Так или иначе, HashSet для победы.
Если у вас есть библиотека коллекций Google, ответ Тома можно значительно упростить с помощью 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");
Использование простого цикла - наиболее эффективный способ сделать это.
boolean useLoop(String[] arr, String targetValue) {
for(String s: arr){
if(s.equals(targetValue))
return true;
}
return false;
}
Предоставлено Programcreek
Одно из возможных решений:
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;
Первый более читабельный, чем второй.
Для массивов ограниченной длины используйте следующее (согласно camickr). Это медленно для повторных проверок, особенно для более длинных массивов (линейный поиск).
Arrays.asList(...).contains(...)
Для повышения производительности при многократной проверке большего набора элементов.
Массив — это неправильная структура. Используйте
TreeSet
и добавьте в него каждый элемент. Он сортирует элементы и имеет быстрый методexist()
(бинарный поиск).Если элементы реализуют
Comparable
и вы хотите, чтобыTreeSet
отсортировались соответствующим образом:Метод
ElementClass.compareTo()
должен быть совместим сElementClass.equals()
: см. Триады не появляются на поле боя? (в наборе Java отсутствует элемент)TreeSet myElements = new TreeSet(); // Делаем это для каждого элемента (реализация *Comparable*) моиЭлементы.добавить(следующийЭлемент); // *В качестве альтернативы*, если массив принудительно предоставляется из другого кода: myElements.addAll(Arrays.asList(myArray)); код>пре>ли>
В противном случае используйте собственный
Comparator
:класс MyComparator реализует Comparator
{ int compareTo (ElementClass element1; ElementClass element2) { // Ваше сравнение элементов // Должно быть согласовано с равенством объектов } логическое равенство (объект другой компаратор) { // Ваше равенство компараторов } } // конструируем TreeSet с компаратором TreeSet myElements = новый TreeSet (новый MyComparator()); // Делаем это для каждого элемента (реализация *Comparable*) моиЭлементы.добавить(следующийЭлемент); код>пре>ли> Выплата: проверка существования некоторого элемента:
// Быстрый бинарный поиск по отсортированным элементам (производительность ~ log(размер)): логическое значение containsElement = myElements.exists(someElement); код>пре>ли>
TreeSet
? HashSet
быстрее (O (1)) и не требует упорядочивания.
В Java 8 используйте потоки.
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);
Проверь это
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").
Попробуй это:
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");
}
Используйте 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.
Используйте следующее (метод 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()
, которые также использовались в других местах.
Если вы не хотите, чтобы регистр регистрировался
Arrays.stream(VALUES).anyMatch(s::equalsIgnoreCase);
Создайте логическое значение, изначально установленное в false. Запустите цикл, чтобы проверить каждое значение в массиве и сравнить со значением, которое вы проверяете. Если вы когда-нибудь найдете совпадение, установите для boolean значение true и остановите цикл. Затем подтвердите, что логическое значение истинно.
Проверить это можно двумя способами
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"));
Б) Это более эффективный метод
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));
}
использование Spliterator
предотвращает ненужное создание List
boolean found = false; // class variable
String search = "AB";
Spliterator<String> spl = Arrays.spliterator( VALUES, 0, VALUES.length );
while( (! found) && spl.tryAdvance(o -> found = o.equals( search )) );
found == true
, если search
содержится в массиве
это работает для массивов примитивов
public static final int[] VALUES = new int[] {1, 2, 3, 4};
boolean found = false; // class variable
int search = 2;
Spliterator<Integer> spl = Arrays.spliterator( VALUES, 0, VALUES.length );
…
Вы можете использовать ArrayUtils.contains
из Apache Commons Lang
public static boolean contains(Object[] array, Object objectToFind)
Обратите внимание, что этот метод возвращает false
, если переданный массив равен null
.
Существуют также методы, доступные для примитивных массивов всех видов.
Примере:
String[] fieldsToInclude = { "id", "name", "location" };
if ( ArrayUtils.contains( fieldsToInclude, "id" ) ) {
// Do some stuff.
}
Попробуйте использовать метод проверки предикатов 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://mytechnologyoughtt.blogspot.com/2019/10/java-8-predicate-test-method-example.html
https://github.com/VipulGulhane1/java8/blob/master/Test.java
Краткое обновление для 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)
О (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
)?
TreeSet
будет O(log n)
. HashSet
масштабируются таким образом, чтобы среднее количество элементов в корзине было примерно постоянным. По крайней мере, для массивов до 2 ^ 30. Могут быть воздействия, скажем, от аппаратных кешей, которые игнорируются при анализе большого О. Также предполагается, что хеш-функция работает эффективно.
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.
}
Поскольку я имею дело с Java низкого уровня, использующим примитивные типы byte и byte [], лучшее, что я получил, - это bytes-java https://github.com/patrickfav/bytes-java кажется прекрасной работой
кратчайшее решение
массив VALUES
может содержать дубликаты
начиная с Java 9
List.of(VALUES).contains(s);
Похожие вопросы
Новые вопросы
java
Java — это высокоуровневый объектно-ориентированный язык программирования. Используйте этот тег, если у вас возникли проблемы с использованием или пониманием самого языка. Этот тег часто используется вместе с другими тегами для библиотек и/или фреймворков, используемых разработчиками Java.
indexOf
иcontains
вjava.util.Arrays
, которые содержат простые циклы. Да, вы можете написать их за 1 минуту; но я все равно пошел на StackOverflow, ожидая найти их где-нибудь в JDK.