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

avatar
Mike Sickler
15 июля 2009 в 00:03
2203477
29
2450

У меня есть String[] с такими значениями:

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

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

Источник
Zack
15 июля 2009 в 00:51
5

Долгий путь, но вы можете использовать цикл for: "for (String s: VALUES) if (s.equals (" MYVALUE ")) return true;

Mike Sickler
15 июля 2009 в 01:20
0

Да, мне было почти неловко задать вопрос, но в то же время я был удивлен, что его не задали. Это один из тех API, с которыми я просто не сталкивался ...

Bill K
29 апреля 2013 в 06:50
3

@ camickr - У меня почти идентичная ситуация с этим: coderhelper.com/a/223929/12943 Он просто продолжает получать голоса, но был просто копией / вставкой из документации sun. Я предполагаю, что оценка зависит от того, сколько помощи вы предоставили, а не от того, сколько усилий вы приложили к ней - а в основном от того, как быстро вы ее публикуете! Может, мы наткнулись на секрет Джона Скита! Что ж, хороший ответ, +1 для вас.

Mr. Boy
12 ноября 2013 в 21:05
2

Если вы используете Apache Commons, то org.apache.commons.lang.ArrayUtils.contains () сделает это за вас.

Alex Mazzariol
20 октября 2014 в 14:52
0

@Zach: вы попадаете в ловушку антипаттерна «если-если», не делайте этого.

Aequitas
20 июля 2015 в 02:41
39

@camickr, потому что люди, подобные мне, задают вопрос в Google, нажимают на результат SO, видят ваш ответ, тестируют его, он работает, голосуют за ответ и уходят.

tucuxi
1 мая 2020 в 10:38
0

Мне очень не хватает простых indexOf и contains в java.util.Arrays, которые оба содержат простые циклы. Да, вы можете написать их за 1 минуту; но я все равно перешел на StackOverflow, ожидая найти их где-нибудь в JDK.

Ответы (29)

avatar
camickr
15 июля 2009 в 00:04
3133
Arrays.asList(yourArray).contains(yourValue)

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


Начиная с java-8 теперь вы можете использовать потоки.

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);
Thomas Owens
15 июля 2009 в 00:06
100

Мне несколько любопытно, насколько эффективно это работает по сравнению с функциями поиска в классе Arrays по сравнению с итерацией по массиву и использованием функции equals () или == для примитивов.

Steve Kuo
15 июля 2009 в 00:07
3

Они оба будут линейным поиском.

Uri
15 июля 2009 в 00:09
0

@Thomas: Я думаю, что asList () может фактически выделить новый объект, который делегирует существующий массив, поэтому вы оплачиваете стоимость выделения. Список поддерживается массивом, поэтому сами элементы не должны перераспределяться.

Joey
15 июля 2009 в 00:09
192

Вы не потеряете много, поскольку asList () возвращает ArrayList, в основе которого лежит массив. Конструктор просто изменит ссылку, так что работы там не так уж и много. И contains () / indexOf () будет повторять и использовать equals (). Однако для примитивов лучше писать самому. Для Strings или других классов разница не будет заметна.

Tom Hawtin - tackline
15 июля 2009 в 01:05
1

Метод Array.asList очень быстр для массивов примитивов. ;)

Nyerguds
13 ноября 2010 в 13:15
18

Странно, NetBeans утверждает, что «Arrays.asList (праздники)» для «int [] праздников» возвращает «список <int []>», а не «список <int>». Он просто содержит один единственный элемент. Это означает, что Contains не работает, поскольку в нем всего один элемент; массив int.

Stas Jaro
10 июня 2011 в 16:43
2

этот метод примерно в 3 раза медленнее, чем базовый цикл поиска.

CromTheDestroyer
14 июня 2011 в 16:51
63

Ньергудс: действительно, для примитивов это не работает. В java примитивные типы не могут быть общими. asList объявлен как <T> List <T> asList (T ...). Когда вы передаете ему int [], компилятор выводит T = int [], потому что он не может вывести T = int, потому что примитивы не могут быть универсальными.

TWiStErRob
17 октября 2012 в 09:16
28

@Joey просто примечание, это ArrayList, но не java.util.ArrayList, как вы ожидаете, реальный возвращенный класс: java.util.Arrays.ArrayList<E> определен как: public class java.util.Arrays {private static class ArrayList<E> ... {}}.

Joey
17 октября 2012 в 10:52
0

Eek. Есть ли причина, по которой это другой ArrayList? o.O

Simon Lehmann
18 июля 2013 в 17:34
11

@ Οеу Поскольку это не «обычный» список ArrayList, Arrays.asList (T ...) «возвращает список фиксированного размера, поддерживаемый указанным массивом». Arrays.ArrayList - это просто «тонкая» оболочка списка вокруг существующего массива. Самое главное, вы не можете добавлять или удалять элементы, потому что он не выделяет собственный массив, а напрямую использует оригинал. Это делает его очень дешевым в использовании, поскольку не требуется никакого копирования, он просто сохраняет ссылку на исходный массив. Так что не бойтесь использовать Arrays.asList (T ...), это не дорого.

Geek
30 августа 2013 в 06:19
0

@Joey, вы написали: «Конструктор просто изменит ссылку, так что там не так много работы». какой конструктор?

camickr
7 декабря 2013 в 04:31
2

@Loc, полностью согласен, я подверг сомнению все голоса "за" 2 года назад, когда их было 75. На самом деле должно быть ограничение в 10 на любой ответ. Ответ не должен использоваться в конкурсе на популярность, только чтобы указать, что это ответ, который ОП должен рассмотреть для решения данного вопроса.

fool4jesus
21 апреля 2014 в 14:44
2

В чем проблема с голосами "за"? Некоторым это экономит время, а более любопытные читают комментарии, узнают больше и поэтому принимают более правильные решения в будущем. Для меня это удачный ответ.

camickr
21 апреля 2014 в 15:04
0

@ fool4jesus, это мой ответ. Прочтите мой комментарий сверху. Нет никакого способа, чтобы любой ответ был настолько хорош. Как вопрос с 700 голосами «за» по сравнению с вопросом с 10 голосами «за» экономит людям «больше» времени? Вам нужно всего лишь несколько голосов, чтобы указать всем, кто читает вопрос, что этот ответ следует рассмотреть.

fool4jesus
22 апреля 2014 в 00:20
0

Я прочитал ваш комментарий (как я предлагал, люди должны :-). Я просто не согласен. На мой взгляд, количество положительных голосов может указывать на превосходный ответ, но, возможно, даже больше на частоту вопроса. Я сам занимаюсь программированием на java в течение многих лет, но я не отслеживаю все последние дополнения к языку и хотел бы быстро проверить здравомыслие, есть ли какие-либо лучшие способы выполнить эту часто используемую функцию. Вы бы почувствовали себя лучше, если бы я забрал свой голос?

Jack
8 октября 2014 в 10:27
0

Этот метод не работает с примитивами! Я обнаружил это только после того, как попытался проделать то же самое с массивом целых чисел.

Stijn de Witt
10 ноября 2014 в 13:41
0

@ fool4jesus «количество положительных голосов может указывать на превосходный ответ, но, возможно, даже больше на частоту вопроса». Согласовано! Я вообще-то думаю, что оценка каким-то образом даже влияет на рейтинг в поиске Google. Таким образом, хорошие ответы на общие вопросы будут занимать высокие места в рейтингах. Звучит неплохо!

user4229245
2 мая 2015 в 15:15
1

Извините, но это хороший ответ только для конкретного примера, когда массив небольшой. Но как решение общего назначения? Преобразование массива в коллекцию только для того, чтобы вы могли использовать эту коллекцию для просмотра самой себя и сообщить вам, существует ли в ней что-то? Ужасный.

Peter Cordes
11 сентября 2015 в 09:54
2

@ tgm1024: как другие объясняли в комментариях выше ваших, это просто тонкая оболочка, которая не копирует. coderhelper.com/questions/1128723/…

user4229245
11 сентября 2015 в 13:05
0

@PeterCordes, дело не в копировании. Эта «тонкая оболочка» не является тонкой оболочкой - это вызов метода для каждого отдельного доступа. Для действительно больших массивов всегда лучше оставить это и позволить компилятору предоставить код доступа. На самом деле, это не лучшее решение общего назначения, если часть определения «общего назначения» включает вероятность того, что большие наборы данных уже в форме массива.

Peter Cordes
11 сентября 2015 в 13:36
0

@ tgm1024: Я думал, что JVM неплохо справляются с оптимизацией тривиальных вызовов методов, которые просто возвращают A[i] или что-то в этом роде. Это должно быть легко по сравнению с большинством оптимизаций компилятора, а также действительно эффективно, так как это происходит очень часто.

user4229245
11 сентября 2015 в 13:52
1

@PeterCordes, ну, тогда я оставлю это здесь, потому что какая бы оптимизация ни происходила с коллекциями, вы, вероятно, превысите это с массивами, , если компилятор не может управлять стилем (ptr ++) оптимизации, основанные на подсказках по сбору. Но будьте осторожны с микротестами. Их очень очень сложно правильно выполнять с Java. В любом случае, это , а не о копировании данных.

Si8
9 апреля 2016 в 23:09
0

А как насчет строки вместо int?

Gilberto Ibarra
30 июня 2016 в 16:02
0

Для примитивов мы можем сделать что-то вроде этого: public Integer keyCode [] = {KeyEvent.KEYCODE 0};

Salah Alshaal
7 июля 2016 в 07:01
0

Это произвело java.lang.NoClassDefFoundError: IntStream с использованием Java8 на Android

Christophe Weis
3 марта 2017 в 07:29
0

Будьте осторожны при использовании массива строк, их следует сравнивать с методом String.equals, а не с ==!

Asqiir
21 апреля 2018 в 13:10
0

Из любопытства: как contains проверяет, есть ли он в массиве? Использует ли он equals или ==?

eigenfield
13 февраля 2020 в 06:36
0

Как насчет массива байтов byte[]?

Luke
24 июня 2020 в 04:32
1

В ответе должен быть приведен пример метода apache ArrayUtils.contains, поскольку он, вероятно, будет быстрее.

camickr
24 июня 2020 в 14:10
0

@ Люк, не должно быть. Ответ был разработан, чтобы быть простым и использовать классы JDK. Он не был разработан для принуждения пользователей к загрузке сторонних классов. Речь также не шла о скорости / эффективности. Добавьте его как свой ответ, если считаете, что это так важно.

ChuckZHB
24 марта 2021 в 08:41
0

Я вижу много способов сделать это, но почему Java не предоставляет простой встроенный метод contains для массива, содержащего проверку? Какая неудача.

Vitaly
24 июня 2021 в 09:13
1

Также предлагается этот способ: boolean contains = Arrays.asList(values).contains("s");

avatar
Kaplan
6 марта 2021 в 06:45
2

кратчайшее решение
массив VALUES может содержать дубликаты <656782016532016> <175367> начиная с Java 9

List.of(VALUES).contains(s);
avatar
eigenfield
26 февраля 2020 в 08:19
1

Поскольку я имею дело с Java низкого уровня, использующим примитивные типы byte и byte [], лучшее, что я получил, - это bytes-java https://github.com/patrickfav / bytes-java кажется прекрасной работой

avatar
Vipul Gulhane
2 октября 2019 в 15:24
1

Попробуйте использовать метод проверки предикатов 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://mytechnologyaught.blogspot.com/2019/10/java-8-predicate-test-method-example.html

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

avatar
Syed Salman Hassan
4 августа 2019 в 13:29
-2

Проверить это можно двумя способами

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));
}
Atuos
22 августа 2019 в 16:04
1

Преобразование строки абсурдно неэффективно, а решение неверно, например contains (",") вернет истину.

avatar
Akhil babu K
21 сентября 2018 в 17:16
3

Если вы не хотите, чтобы регистр регистрировался

Arrays.stream(VALUES).anyMatch(s::equalsIgnoreCase);
avatar
mandy1339
17 мая 2018 в 19:37
1

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

avatar
TheArchon
30 апреля 2015 в 02:57
3

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.
}
avatar
Shineed Basheer
28 апреля 2015 в 06:40
7

В 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);
avatar
Christian Giménez
14 декабря 2014 в 21:49
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");
      }
  }
}
avatar
Abhishek Oza
23 июля 2014 в 13:25
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);
    }
}

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(), которые также использовались в других местах.

avatar
AndroidGeek
25 июня 2014 в 07:24
8

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

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;

Первый более читабельный, чем второй.

avatar
SubbaRao Boddu
5 июня 2014 в 10:19
3

Отметьте это

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
    }
}
Bernhard Barker
4 января 2018 в 12:42
1

Это не работает - он будет вводить else для каждый элемент , который не соответствует (поэтому, если вы ищете «AB» в этом массиве, он будет идти туда 3 раза, поскольку 3 значения не являются "AB").

avatar
Sireesh Yarlagadda
7 мая 2014 в 19:14
84

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

  1. Использование List:

    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) {  
        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
Will Sherwood
27 марта 2015 в 01:33
5

ваш пример двоичного поиска должен возвращать> 0;

mbelow
25 мая 2016 в 15:22
6

Почему? Я думаю, он должен вернуть a> -1, поскольку 0 означает, что он содержится в заголовке массива.

Yoory N.
30 ноября 2017 в 13:08
2

Первый вариант с (a >= 0) был правильным, просто проверьте документы, они говорят: «Обратите внимание, что это гарантирует, что возвращаемое значение будет> = 0, если и только если ключ найден».

Willians Martins
21 мая 2019 в 20:57
0

Почему работает с String, а не с int? статическое логическое значение существует (int [] int, int k) {return Arrays.asList (int) .contains (k); }

avatar
Ryan
7 апреля 2014 в 19:53
6

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

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

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

Samuel Edwin Ward
21 декабря 2015 в 02:45
0

Это вызовет исключение нулевого указателя, если массив содержит пустую ссылку перед целевым значением.

TheArchon
3 мая 2016 в 01:37
1

оператор if должен быть: if (targetValue.equals (s)), потому что String equals имеет средство проверки instanceof.

trilogy
2 августа 2019 в 17:12
0

вместо этого используйте Objects.equals (obj1, obj2), чтобы быть нулевым.

avatar
assylias
13 марта 2014 в 14:53
37

В 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);
}
skiwi
7 апреля 2014 в 20:11
3

Также стоит отметить примитивные специализации.

mkobit
15 декабря 2014 в 17:21
0

Кроме того, anyMatch JavaDoc утверждает, что это "...May not evaluate the predicate on all elements if not necessary for determining the result.", поэтому, возможно, не потребуется продолжать обработку после нахождения совпадения.

avatar
Mr.G
7 декабря 2013 в 04:19
4

Попробуйте это:

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");
}
avatar
Avenger
30 мая 2013 в 06:59
2

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

Пример:

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

ложь - не существует

ataylor
27 июня 2013 в 20:03
4

Array.BinarySearch и Array.FindIndex являются методами .NET и не существуют в Java.

mente
28 августа 2013 в 07:27
0

@ataylor есть Arrays.binarySearch в java. Но ты прав, никакого Arrays.findIndex

Dorian Gray
19 декабря 2019 в 21:17
0

Следует отметить: The array must be sorted prior to making this call. If it is not sorted, the results are undefined.

avatar
Glen Best
20 мая 2013 в 07:34
5
  1. Для массивов ограниченной длины используйте следующее (как указано в camickr ). Это медленно для повторных проверок, особенно для более длинных массивов (линейный поиск).

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

    • Массив имеет неправильную структуру. Используйте 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);
      
Sean Owen
30 декабря 2013 в 09:53
4

Зачем возиться с TreeSet? HashSet быстрее (O (1)) и не требует заказа.

avatar
icza
28 сентября 2012 в 07:45
163

Просто реализуйте это вручную:

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
9 октября 2012 в 14:08
1

Какая разница в производительности между этим решением и принятым ответом?

icza
10 октября 2012 в 11:25
9

@Phoexo Это решение, очевидно, быстрее, потому что принятый ответ превращает массив в список и вызывает метод contains () в этом списке, в то время как мое решение в основном делает то, что будет делать только contains ().

FirstName LastName
14 января 2013 в 16:38
1

е == v || v! = null && v.equals (e) --- Первая часть оператора OR сравнивает e и v. Вторая часть делает то же самое (после проверки, что v не равно нулю). Зачем вам такая реализация вместо просто (e == v). Не могли бы вы мне это объяснить?

icza
15 января 2013 в 08:39
10

@AlastorMoody e == v выполняет очень быструю проверку равенства ссылок. Если в массиве есть такой же объект (такой же по ссылке), он будет найден быстрее. Если это не тот же экземпляр, он все равно может быть таким же, как заявлено методом equals (), это то, что проверяется, если ссылки не совпадают.

phreakhead
2 апреля 2013 в 19:30
24

Почему эта функция не является частью Java? Неудивительно, что люди говорят, что Java раздута ... посмотрите на все приведенные выше ответы, которые используют кучу библиотек, когда все, что вам нужно, - это цикл for. Дети в наши дни!

Steve Kuo
11 января 2014 в 00:37
4

@phreakhead Это часть Java, см. Collection.contains(Object)

Axel
11 февраля 2014 в 07:41
12

@icza Если вы посмотрите на источник Arrays и ArrayList, окажется, что это не обязательно быстрее, чем версия, использующая Arrays.asList(...).contains(...). Накладные расходы на создание ArrayList чрезвычайно малы, а ArrayList.contains() использует более умный цикл (фактически он использует два разных цикла), чем показанный выше (JDK 7).

icza
11 февраля 2014 в 14:52
0

@Axel Ты прав. Для небольших массивов это определенно быстрее. Для больших массивов это было бы немного медленнее, но снова стало бы немного быстрее, если бы использовались 2 цикла, основанные на том, что искомое значение равно нулю или нет. Я думал об этих двух петлях раньше, но оставил их для простоты.

Skylar Saveland
3 июля 2014 в 17:10
2

См. Также: картофельное программирование.

deworde
1 апреля 2015 в 13:42
1

-1: Если вам нужна производительность, то правильнее было бы инкапсулировать массив и кэшировать проверки, которые вам нужны при назначении, а не повторять его каждый раз, когда вам нужно выполнить проверку (и, честно говоря, вероятно, не запускать внутри JVM). Если вы этого не сделаете, это будет более многословным и менее удобным в обслуживании.

icza
1 апреля 2015 в 14:16
4

@deworde Я не согласен. Если вам нужна производительность в отношении операции contains, вообще не используйте массивы (а лучше HashSet). Вопрос был о массивах, поэтому я показал, как это можно сделать с массивами. И первое решение - это простой цикл, совсем несложный. А также, если массив уже задан и у вас мало или совсем нет выбора для выбора структуры данных, улучшенная версия имеет значение.

user4229245
2 мая 2015 в 15:24
1

Проблема, однако, в том, что концептуально вы не хотите учить людей брать одну потенциально большую структуру данных (массив), а затем преобразовывать ее в другую большую структуру (коллекцию) ТОЛЬКО, чтобы вы могли просматривать эту вторую структуру. Самая важная причина состоит в том, что 1. это совершенно не нужно, и 2. фактическая реализация этого механизма поиска по коллекции должна рассматриваться как непрозрачная, потому что она может измениться в будущих версиях Java. Плохая идея только из принципа.

Steves
23 июня 2016 в 11:15
1

en.wikipedia.org/wiki/Loop-invariant_code_motion «улучшение» бесполезно, любой разумный компилятор (включая C1 и C2 в HotSpot) переместит нулевую проверку за пределы цикла, потому что параметр является окончательным и не может изменять.

Steves
23 июня 2016 в 11:16
0

Более того, вы можете использовать Objects.equals, чтобы полностью избежать проверки. Вызов будет встроенным, что приведет к тому же машинному коду и той же производительности.

AustrianDude
5 июля 2017 в 15:09
0

Если вы не хотите бросать NPE, когда "array" имеет значение NULL, соответствующая часть должна быть окружена проверкой NULL -> if (array! = Null).

avatar
jhodges
19 сентября 2012 в 14:13
11

Если у вас есть библиотека коллекций 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");
avatar
Intracer
31 мая 2011 в 13:17
222

Вы можете использовать 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.
}
Jason
7 декабря 2012 в 17:48
4

@ max4ever Я согласен, но это все же лучше, чем "катить самостоятельно", и его легче читать, чем необработанный способ java.

slamborne
31 января 2014 в 02:39
2

пакет: org.apache.commons.lang.ArrayUtils

GuiSim
22 апреля 2014 в 19:30
42

@ max4ever Иногда у вас уже есть эта библиотека (по другим причинам), и это совершенно правильный ответ. Я искал это и уже полагаюсь на Apache Commons Lang. Спасибо за этот ответ.

Buffalo
9 марта 2015 в 11:59
1

Или вы можете просто скопировать метод (и зависимости, если они есть).

Marcel
23 февраля 2016 в 15:19
0

Это лучший способ, если в вашем проекте уже есть язык Apache Commons. Если у тебя его нет. Вы должны написать свой единственный метод.

Kenyakorn Ketsombut
12 августа 2016 в 13:11
10

@ max4ever Большинство приложений для Android минимизированы Proguard, помещая в приложение только те классы и функции, которые вам нужны. Это равносильно свертыванию собственного или копированию исходного кода apache. И тому, кто не пользуется этой минимизацией, не нужно жаловаться на 700 или 78 Кб :)

Joshua Detwiler
26 июня 2017 в 17:52
1

Иногда мы стреляем лазерами по комарам. Ничего страшного в этом нет;)

Andrew
25 июня 2018 в 14:38
1

Спасибо. Одно из преимуществ этого решения по сравнению с другими заключается в том, что оно должно быть легко читаемым для всех, например если value находится в some range of values, делайте A, если это в some other range of values, делайте B и т.д. скорость.

avatar
Mark Rhodes
20 января 2011 в 13:58
40

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

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

Затем вы можете сделать (как указано выше):

STRINGS.contains("the string you want to find");
avatar
not
11 июня 2010 в 02:37
13

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

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

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

  1. HashSet
  2. asList
  3. сортировка и двоичная

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

  1. HashSet
  2. Двоичный
  3. asList

Так или иначе, HashSet для победы.

Skylar Saveland
3 июля 2014 в 17:21
2

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

avatar
camickr
15 июля 2009 в 01:28
51

Как бы то ни было, я провел тест, сравнивая 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));
    }
}
Erik
30 мая 2013 в 09:16
6

Я не понимаю этот код. Вы сортируете «строки» массива и используете один и тот же (отсортированный) массив в обоих вызовах binarySearch. Как это может показать что-либо, кроме оптимизации времени выполнения HotSpot? То же самое и с вызовом asList.contains. Вы создаете список из отсортированного массива, а затем содержит в нем наибольшее значение. Конечно, на это потребуется время. В чем смысл этого теста? Не говоря уже о том, что это неправильно написанный микробенчмарк.

Erik
30 мая 2013 в 09:18
0

Кроме того, поскольку двоичный поиск может применяться только к отсортированному набору, сортировка и поиск - единственный возможный способ использования двоичного поиска.

Thor84no
24 октября 2013 в 12:25
0

Сортировка могла уже быть выполнена по ряду других причин, например, его можно было отсортировать при инициализации и никогда не изменять. Само по себе время поиска можно использовать. Однако это не совсем удачный пример микробенчмаркинга. Микробенчмарки, как известно, сложно реализовать в Java, и они должны, например, включать выполнение тестового кода, достаточного для оптимизации точки доступа перед запуском фактического теста, не говоря уже о запуске фактического тестового кода чаще, чем ОДИН РАЗ с таймером. Примеры ошибок

Steve Kuo
11 января 2014 в 00:39
7

Этот тест ошибочен, поскольку он запускает все 3 теста в одном и том же экземпляре JVM . Более поздние тесты могут выиграть от более ранних, разогревающих кеш, JIT и т. Д.

dragn
11 сентября 2014 в 13:47
4

Этот тест на самом деле совершенно не связан. Сортировка и поиск - это линейная (n * log (n)) сложность, двоичный поиск - логарифмический, а ArrayUtils.contains - очевидно линейный. Сравнивать эти решения бесполезно, поскольку они находятся в совершенно разных классах сложности.

avatar
Tom Hawtin - tackline
15 июля 2009 в 01:18
17

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

enum Values {
    AB, BC, CD, AE
}

try {
    Values.valueOf(s);
    return true;
} catch (IllegalArgumentException exc) {
    return false;
}
James P.
2 июня 2011 в 18:20
1

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

avatar
Tom Hawtin - tackline
15 июля 2009 в 01:13
394

Краткое обновление для 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 коллекций предсказуемо все еще отсутствуют неизменяемые типы коллекций, а синтаксис по-прежнему слишком подробный, на мой вкус.)

Drew Noakes
25 апреля 2011 в 06:54
191

За исключением того, что это O (N) для создания коллекции в первую очередь :)

Xr.
12 октября 2011 в 19:39
65

Если он статичен, он, вероятно, будет использоваться довольно много раз. Таким образом, время, затрачиваемое на инициализацию набора, имеет хорошие шансы быть довольно маленьким по сравнению со стоимостью большого количества линейных поисков.

Tom Hawtin - tackline
7 марта 2012 в 13:23
1

При создании коллекции будет преобладать время загрузки кода (которое технически составляет O (n), но практически постоянно).

Basil Bourque
29 августа 2014 в 05:04
2

@ TomHawtin-tackline Почему вы говорите «в частности, нам нужен набор»? В чем преимущество Set (HashSet) в этом случае? Почему «ссылочный массив» плох (под «ссылочным массивом» вы подразумеваете список ArrayList, поддерживаемый массивом, сгенерированным вызовом Arrays.asList)?

Tom Hawtin - tackline
29 августа 2014 в 13:29
1

@BasilBourque Проблема, которую пытаются решить, состоит в том, чтобы определить, находится ли значение в наборе значений. Set очень хорошо подходит. / Под «эталонным массивом» я подразумеваю массив ссылочных типов на языке Java. Массивы примитивов, хотя и невелики, немного не хватает эффективных альтернатив без некоторой необходимой неуклюжей библиотеки. Более поздняя версия Java могла поддерживать неизменяемые типы selfless / value, что могло бы изменить ситуацию.

nmr
9 сентября 2014 в 21:49
0

разве этот поиск на самом деле не O (log (n))

Tom Hawtin - tackline
9 сентября 2014 в 23:51
6

@nmr A TreeSet будет O(log n). HashSet масштабируются таким образом, чтобы среднее количество элементов в сегменте было примерно постоянным. По крайней мере, для массивов до 2 ^ 30. Могут быть воздействия, скажем, от аппаратных кешей, которые игнорируются при анализе большого О. Также предполагается, что хеш-функция работает эффективно.

Thorbjørn Ravn Andersen
5 июля 2015 в 11:22
0

вам нужно перебрать массив, чтобы создать коллекцию. На). Затем вы можете утверждать, что амортизировано или аналогично, это выравнивается, но у вас должен быть где-то шаг O (n).

Bill K
24 сентября 2018 в 20:44
1

Это совершенно правильный ответ. Большинство комментаторов упускают из виду то, что если бы вы изначально помещали объекты в коллекцию, у вас не было бы намного больше времени, чем на создание массива. Просто избегайте использования массивов, если вы абсолютно не уверены, что ничего другого не подойдет (для повышения производительности), используя массив, потому что вы думаете, что он будет быстрее без тестирования, чтобы увидеть, действительно ли коллекция действительно слишком медленная, в первую очередь, является прекрасным примером преждевременного оптимизация.

Paulo Oliveira
11 июня 2019 в 14:21
0

Для меня это решение с Set более элегантно, чем принятый ответ. Спасибо.

Minn
18 августа 2019 в 20:37
2

Это не отвечает на вопрос о массиве. Вы просто говорите «не используйте массивы», что не является решением. Кроме того, вы просто говорите «Х - это плохо», но не объясняете, почему, что всегда плохо для ответа.

kaya3
31 октября 2019 в 01:29
1

По крайней мере, в реализации OpenJDK четырехпараметрический метод Set.of не возвращает структуру данных HashSet; для такого небольшого количества элементов это было бы неэффективно. Смотрите код здесь: hg.openjdk.java.net/jdk9/jdk9/jdk/file/86f19074aad2/src/…

Tom Hawtin - tackline
31 октября 2019 в 02:08
1

@ kaya3 Хорошо. Big-O предназначен для достаточно большого (т.е. довольно большого) n. Я считаю, что C # имеет гибридную реализацию с первого дня или, возможно, 2.0.

avatar
Uri
15 июля 2009 в 00:05
72

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

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

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

Thomas Owens
15 июля 2009 в 00:10
1

Кроме того, как я сказал в своем ответе, если вы используете класс Arrays, вы можете отсортировать массив, а затем выполнить двоичный поиск по только что отсортированному массиву.

Uri
15 июля 2009 в 00:14
1

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

avatar
Thomas Owens
15 июля 2009 в 00:05
28

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

Thomas Owens
15 июля 2009 в 00:06
0

Для этого вы можете использовать функции сортировки в том же классе ... Я должен добавить это к своему ответу.

Joey
15 июля 2009 в 00:10
1

Тогда, я думаю, это будет стоить больше, чем подход asList (). Contains (). Если вам не нужно делать эту проверку очень часто (если честно, если это просто статический список значений, которые можно отсортировать для начала).

Thomas Owens
15 июля 2009 в 00:13
0

Истинный. Есть много переменных, которые могут быть наиболее эффективными. Тем не менее, неплохо иметь варианты.

O.O.Balance
14 января 2018 в 00:11
0

Вот код, который это делает: coderhelper.com/a/48242328/9131078

arunwithasmile
14 февраля 2018 в 09:51
0

Сортировка всего массива для поиска - это дорого. Мы можем использовать то же процессорное время для самого поиска лайнера. Я предпочитаю бинарный поиск по коллекции, которая заранее построена в отсортированном порядке.