Как определить, содержит ли массив определенное значение в Java?

1815

У меня есть String[] со значениями, например:

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

Учитывая String s, есть ли хороший способ проверить, содержит ли VALUES s?

  • 3
    Долгий путь, но вы можете использовать цикл for: "for (String s: VALUES) if (s.equals (" MYVALUE ")) возвращает true;
  • 0
    Да, я был почти смущен, чтобы задать вопрос, но в то же время был удивлен, что он не был задан. Это один из тех API, с которыми я просто не сталкивался ...
Показать ещё 5 комментариев
Теги:
arrays

27 ответов

2479
Лучший ответ
Arrays.asList(yourArray).contains(yourValue)

Предупреждение: это не работает для массивов примитивов (см. Комментарии).


Начиная с вы можете использовать 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);
  • 78
    Мне несколько любопытно, как это можно сравнить с функциями поиска в классе Arrays, с итерациями по массиву и использованием функции equals () или == для примитивов.
  • 3
    Они оба были бы линейным поиском.
Показать ещё 26 комментариев
327

Просто, чтобы очистить код до начала. У нас (исправлено):

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 - его можно даже обнародовать).

"Учитывая String s, есть ли хороший способ проверить, содержит ли VALUES s?"

VALUES.contains(s)

О (1).

  • 173
    За исключением того, что это O (N), чтобы создать коллекцию в первую очередь :)
  • 55
    Если он статичен, он, вероятно, будет использоваться довольно много раз. Таким образом, время, затрачиваемое на инициализацию набора, имеет хорошие шансы быть довольно маленьким по сравнению со стоимостью многих линейных поисков.
Показать ещё 7 комментариев
173

Вы можете использовать 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.
}
  • 107
    300 КБ библиотека для 78 КБ приложения для Android, не всегда хорошо
  • 4
    @ max4ever Я согласен, но это все же лучше, чем "сворачивать свои", и легче читать, чем сырой Java-способ.
Показать ещё 7 комментариев
145

Я удивлен, что никто не предложил просто реализовать его вручную:

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;
}
  • 1
    Какая разница в производительности между этим решением и принятым ответом?
  • 8
    @Phoexo Это решение, очевидно, быстрее, потому что принятый ответ оборачивает массив в список и вызывает метод contains () в этом списке, в то время как мое решение в основном делает то, что будет делать только only ().
Показать ещё 13 комментариев
65

Если массив не отсортирован, вам придется перебирать все и делать вызов равным для каждого.

Если массив отсортирован, вы можете выполнить двоичный поиск, там один в классе Arrays.

Вообще говоря, если вы собираетесь выполнять много проверок членства, вы можете захотеть сохранить все в наборе, а не в массиве.

  • 1
    Также, как я сказал в своем ответе, если вы используете класс Arrays, вы можете отсортировать массив, а затем выполнить бинарный поиск по вновь отсортированному массиву.
  • 1
    @ Томас: я согласен. Или вы можете просто добавить все в TreeSet; такая же сложность. Я бы использовал массивы, если они не меняются (возможно, сохраните немного локальности памяти, так как ссылки расположены непрерывно, а строки - нет). Я бы использовал набор, если это изменится со временем.
58

Четыре разных способа проверки, если массив содержит значение

1) Использование списка:

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

2) Использование Set:

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

3) Используя простой цикл:

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

4) Использование Arrays.binarySearch():

Код ниже неверен, он указан здесь для полноты. binarySearch() может ТОЛЬКО использоваться на отсортированных массивах. Вы увидите, что результат ниже. Это лучший вариант при сортировке массива.

public static boolean binarySearch(String[] arr, String targetValue) {  
            int a = Arrays.binarySearch(arr, targetValue);
            return a > 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
  • 5
    ваш пример бинарного поиска должен возвращать> 0;
  • 6
    Зачем? Я думаю, что он должен возвращать> -1, так как 0 будет означать, что он содержится в начале массива.
Показать ещё 1 комментарий
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() будет содержать путь. Если у вас много поисков, может быть целесообразно отсортировать массив, чтобы вы могли использовать двоичный поиск. Все зависит от вашего приложения.

Я бы подумал, что это те результаты, которые ожидали большинство людей. Вот тестовый код:

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));
    }
}
  • 6
    Я не понимаю этот код. Вы сортируете массив 'strings' и используете один и тот же (отсортированный) массив в обоих вызовах binarySearch. Как это может показать что-нибудь кроме оптимизации времени выполнения HotSpot? То же самое с вызовом asList.contains. Вы создаете список из отсортированного массива и затем содержит в нем самое высокое значение. Конечно, это займет время. В чем смысл этого теста? Не говоря уже о том, что он неправильно написан
  • 0
    Кроме того, поскольку бинарный поиск может применяться только к отсортированному набору, сортировка и поиск являются единственным возможным способом использования бинарного поиска.
Показать ещё 3 комментария
31

С 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);
}
  • 3
    Стоит также отметить примитивные специализации.
  • 0
    Кроме того, anyMatch JavaDoc заявляет, что он "...May not evaluate the predicate on all elements if not necessary for determining the result." , поэтому может не потребоваться продолжить обработку после нахождения соответствия.
30

Вместо того, чтобы использовать синтаксис инициализации быстрого массива, вы можете просто инициализировать его как список сразу же, используя метод Arrays.asList, например:

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

Затем вы можете сделать (например, выше): STRINGS.contains("the string you want to find");

22

Вы можете использовать класс Arrays для выполнения двоичного поиска значения. Если ваш массив не отсортирован, вам придется использовать функции сортировки в том же классе для сортировки массива, а затем выполнить поиск через него.

  • 0
    Вы можете использовать функции сортировки в том же классе, чтобы сделать это ... Я должен добавить это к моему ответу.
  • 1
    Я думаю, что, вероятно, будет стоить дороже, чем метод asList (). Contains (). Если вам не нужно делать эту проверку очень часто (но если это просто статический список значений, которые можно отсортировать для начала, если честно).
Показать ещё 4 комментария
15

ObStupidAnswer (но я думаю, что там где-то есть урок):

enum Values {
    AB, BC, CD, AE
}

try {
    Values.valueOf(s);
    return true;
} catch (IllegalArgumentException exc) {
    return false;
}
  • 1
    Бросок исключений, по-видимому, тяжел, но это был бы новый способ проверки значения, если он работает. Недостатком является то, что перечисление должно быть определено заранее.
11

На самом деле, если вы используете HashSet, как предложил Том Хотин, вам не нужно беспокоиться о сортировке, а ваша скорость такая же, как при двоичном поиске на предварительно отсортированном массиве, возможно, даже быстрее.

Все зависит от того, как ваш код настроен, очевидно, но с того места, где я стою, порядок будет:

В массиве Unsorted:

  • HashSet
  • asList
  • сортировка и двоичный

В отсортированном массиве:

  • HashSet
  • Binary
  • asList

Так или иначе, HashSet ftw

  • 2
    Членство в HashSet должно быть O (1), а двоичный поиск в отсортированной коллекции - O (log n).
9

Если у вас есть библиотека коллекций google, ответ Tom можно упростить, используя 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");
7

Одно из возможных решений:

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

В 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);
  • 6
    Есть ли преимущества у этого подхода?
  • 0
    Это не отвечает на вопрос.
6

Разработчики часто делают:

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;

Первая из них более читаема, чем вторая.

4

Использование простого цикла - наиболее эффективный способ сделать это.

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

Предоставлено Programcreek

  • 0
    Это вызовет исключение нулевого указателя, если массив содержит нулевую ссылку перед целевым значением.
  • 1
    оператор if должен быть: if (targetValue.equals (s)), поскольку String equals имеет проверку экземпляра.
3
  • Для массивов ограниченной длины используйте следующее (как указано camickr). Это медленно для повторных проверок, особенно для более длинных массивов (линейный поиск).

     Arrays.asList(...).contains(...)
    
  • Для быстрой работы, если вы неоднократно проверяете более широкий набор элементов

    • Массив - неправильная структура. Используйте 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));
      
    • В противном случае используйте собственный 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);
      
    • Выплата: проверьте наличие какого-либо элемента:

      // Fast binary search through sorted elements (performance ~ log(size)):
      boolean containsElement = myElements.exists(someElement);
      
  • 4
    Зачем беспокоиться о TreeSet ? HashSet работает быстрее (O (1)) и не требует упорядочивания.
2

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.
}
  • 0
    Arrays.asList не является O (n). Это просто легкая обертка. Посмотрите на реализацию.
1

Если вы не хотите, чтобы это было чувствительно к регистру

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

Это может быть просто:

String[] VALUE = new String[] {"AB","BC","CD","AE"};
Arrays.asList(VALUE).contains(s);
1

Я очень опаздываю, чтобы присоединиться к этой дискуссии, но поскольку мой подход к решению этой проблемы, когда я столкнулся с ней несколько лет назад, немного отличался от других ответов, уже размещенных здесь, я публикую это решение, которое я использовал в на этот раз, здесь, в случае, если кто-то найдет это полезным: (< <20 > в 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(), которые также использовались в других местах.

  • 0
    Я очень поздно присоединяюсь к этой дискуссии, но, поскольку мой подход к решению этой проблемы, когда я столкнулся с ней несколько лет назад, несколько отличался от других ответов, уже опубликованных здесь, я публикую свое решение, которое я использовал в то время, здесь, на случай, если кто-нибудь найдет это полезным.
1

Проверьте это

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
    }
}
  • 0
    Это все еще работает, хотя и менее эффективно
  • 1
    Это не работает - он вводит else для каждого элемента, который не совпадает (поэтому, если вы ищете «AB» в этом массиве, он пойдет туда 3 раза, поскольку 3 значения не совпадают » AB ").
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");
}
1

Используйте Array.BinarySearch(array,obj) для поиска данного объекта в массиве или нет. Пример:

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

false - не существует

  • 3
    Обратите внимание, что массив должен быть отсортирован, чтобы это работало.
  • 4
    Array.BinarySearch и Array.FindIndex являются методами .NET и не существуют в Java.
Показать ещё 1 комментарий
0

Вот мой простой код, используя класс Arrays из пакета util. Это можно сделать многими другими способами, но, поставив вопрос, этот подход пришел мне на ум.

String a[] = {"abc","xyz","pqr"};
System.out.println(Arrays.asList(a).contains("abc")); //will return true
System.out.println(Arrays.asList(a).contains("abcd")); // will return false
-2

Создайте логическое значение, первоначально заданное как false. Запустите цикл, чтобы проверить каждое значение в массиве и сравнить с значением, которое вы проверяете. Если вы когда-либо получаете совпадение, установите boolean в true и остановите цикл. Тогда утвердим, что логическое значение истинно.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню