Питання Як перевірити, чи масив містить певне значення?


Я маю String[] з такими значеннями:

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

Дано String s, чи є хороший спосіб перевірити, чи є VALUES містить s?


1855
2017-07-15 00:03


походження


Довгий шлях навколо нього, але ви можете використовувати для циклу: "for (String s: VALUES) if (s.equals (" MYVALUE ")) повертають істину; - Zack
Чому люди ще дають відповіді на цю відповідь (зараз 75)? Його 2 роки і дуже проста відповідь. Все, що я зробив, було вказувати когось на метод API. Я не думаю, що будь-яка відповідь настільки дивовижна, що вона заслуговує на цю лунцювальну верхівку. - camickr
@ camickr На ваше запитання, я вирішив це питання і вашу відповідь - тепер- тому що це врятувало мене 30 хвилин та 20 рядків коду, що пише потворно для циклів, - тепер-. Не прочитав це три роки тому. (BTW, дякую :)) - Pursuit
@ camickr - У мене майже однакова ситуація з цим: stackoverflow.com/a/223929/12943  Він просто продовжує отримувати голоси - це просто копія / вставка з документації сонця. Я думаю, оцінка заснована на тому, скільки вам надається допомога, а не на те, скільки зусиль ви вкладаєте - і в основному, як швидко ви його опублікуєте! Може, ми натрапили на таємницю Джона Скета! Добре гарна відповідь, +1 для вас. - Bill K
@camickr, тому що люди, як і я, Google, ставлять питання, клацніть на результат SO, перегляньте вашу відповідь, протестувати, він працює, оновити відповідь, а потім залишити. - Aequitas


Відповіді:


Arrays.asList(yourArray).contains(yourValue)

Попередження: це не працює для масивів примітивів (див. Коментарі).


З тих пір

Тепер ви можете використовувати a Stream щоб перевірити, чи масив int, double або long містить значення (відповідно, використовуючи a IntStream, DoubleStream або LongStream)

Приклад

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

2428
2017-07-15 00:04



Мені трохи цікаво, як працює ця функція порівняно з пошуковими функціями в класі масивів, порівняно з повторенням масиву та використанням функції рівних () або == для примітивів. - Thomas Owens
Ви не втрачаєте багато чого, тому що asList () повертає ArrayList, у якого є масив у своєму серці. Конструктор просто змінить посилання, так що тут не багато роботи. І містить () / indexOf () буде повторювати і використовувати рівними (). Для примітивів вам краще кодувати його самостійно. Для рядків або інших класів різниця не буде помітною. - Joey
Незважаючи на те, NetBeans заявляє, що "Масиви. Список" (свята) для "int [] свят" повертає "список <int []>", а не "список <int>". Він просто містить один єдиний елемент. Значення Contains не працює, оскільки воно має лише один елемент; масив int. - Nyerguds
Nyerguds: насправді, це не працює для примітивів. У java примітивні типи не можуть бути загальними. asList оголошується як <T> Список <T> asList (T ...). Коли ви передаєте int [] в нього, компілятор видає T = int [], оскільки не може визначити T = int, оскільки примітиви не можуть бути загальними. - CromTheDestroyer
@ Джей, просто бічна нотатка, вона є ArrayList, але ні java.util.ArrayListяк ви очікуєте, повернувся справжній клас: java.util.Arrays.ArrayList<E> визначається як: public class java.util.Arrays {private static class ArrayList<E> ... {}}. - TWiStErRob


Просто очистити код, щоб почати з. Ми (виправлено):

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 - це може бути навіть оприлюднено).

"Вказані рядки, чи є хороший спосіб перевірки, чи містить значення" "?"

VALUES.contains(s)

O (1).


309
2017-07-15 01:13



За винятком це O (N), щоб створити колекцію в першу чергу :) - Drew Noakes
Якщо це статичне, воно, ймовірно, буде використовуватися кілька разів. Отже, час, який витрачається на ініціалізацію набору, має хороші шанси бути досить невеликим порівняно з вартістю багатьох лінійних пошуків. - Xr.
Після створення колекції буде домінувати час завантаження коду (що технічно є O (n), але практично постійним). - Tom Hawtin - tackline
@ TomHawtin-tackline Чому ви кажете "зокрема, тут ми хочемо встановити"? У чому полягає перевага Set (HashSet) у цьому випадку? Чому "еталонний масив" поганий (за "еталонним масивом" ви маєте на увазі ArrayList, що підтримується масивом, який генерується за допомогою виклику Arrays.asList)? - Basil Bourque
@ nmr A TreeSet був би O(log n). HashSetS масштабуються таким чином, що середнє число елементів в відро є приблизно постійним. Принаймні для масивів до 2 ^ 30. Можливо, це впливає, скажімо, на апаратні кешування, які ігнорується аналіз big-O. Також передбачається, що функція хеш працює ефективно. - Tom Hawtin - tackline


Ви можете використовувати 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.
}

171
2018-05-31 13:17



Бібліотека 300kb для програми 78kb для Android, не завжди добре - max4ever
@ max4ever я згоден, але це все-таки краще, ніж "прокат вашого власного" і простіше читати, то сировинний Java-спосіб. - Jason
пакет: org.apache.commons.lang.ArrayUtils - slamborne
@ max4ever Іноді у вас вже є ця бібліотека (з інших причин), і це цілком справедлива відповідь. Я шукав цього, і я вже залежав від Apache Commons Lang. Дякую за цю відповідь. - GuiSim
@ max4ever Більшість додатків Android повністю мінімізуються програмою Proguard, додаючи лише ті класи та функції, які вам потрібні у вашому додатку. Це робить його рівним, щоб перемістити вашу власну або копіювати джерело предмету apache. І той, хто не використовує цю мінімізацію, не повинен скаржитися на 700kb або 78kb :) - Kenyakorn Ketsombut


Я здивований, ніхто не пропонував просто виконати це вручну:

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

Удосконалення:

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

142
2017-09-28 07:45



@Phoexo Це рішення, очевидно, швидше, тому що прийнята відповідь замалює масив у список і викликає метод content () у цьому списку, тоді як моє рішення в основному робить те, що містить (). - icza
@AlastorMoody e == v робить контрольну перевірку рівності, яка дуже швидко. Якщо один і той же об'єкт (той же за посиланням) знаходиться в масиві, він буде знайдено швидше. Якщо це не той самий екземпляр, він все ще може бути таким самим, як заявлено методом equals (), це те, що перевіряється, якщо посилання не ті самі. - icza
Чому ця функція не є частиною Java? Не дивно, що люди кажуть, що Java роздутий ... подивіться на всі відповіді вище, що використовують купу бібліотек, коли все, що вам потрібно, це для циклу. Діти в ці дні! - phreakhead
@phreakhead Це частина Java, див Collection.contains(Object) - Steve Kuo
@icza Якщо подивитися на джерело Arrays і ArrayList виявляється, що це не обов'язково швидше, ніж використання версії Arrays.asList(...).contains(...). Накладні витрати на створення ArrayList надзвичайно мала, і ArrayList.contains() використовує більш розумну петлю (насправді вона використовує дві різні петельки), ніж зазначена вище (JDK 7). - Axel


Якщо масив не буде відсортовано, вам доведеться повторити все і зателефонувати рівним на кожному.

Якщо масив сортований, ви можете зробити бінарний пошук, там є один Масиви клас

Взагалі кажучи, якщо ви збираєтеся робити багато чеків на членство, ви можете зберегти все в наборі, а не в масиві.


65
2017-07-15 00:05



Крім того, як я вже сказав у моїй відповіді, якщо ви використовуєте клас масивів, ви можете сортувати масив, після чого виконати бінарний пошук на знову сортованому масиві. - Thomas Owens
@Томас: я згоден. Або ви можете просто додати все до TreeSet; однакова складність Я хотів би використовувати масиви, якщо воно не змінюється (можливо, збережемо трохи місця пам'яті, оскільки посилання розташовані одночасно, хоча рядки не є). Я б використовував цей набір, якщо це з часом зміниться. - Uri


Чотири різних способів перевірки, якщо масив містить значення

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

59
2018-05-07 19:14



ваш приклад двійкового пошуку повинен повертати a> 0; - Will Sherwood
Чому? Я думаю, що він повинен повертати> -1, оскільки 0 означає, що він міститься в голові масиву. - mbelow
Перший варіант з (a >= 0) було правильно, просто перевірте документи, вони говорять: «Зауважте, що це гарантує, що повертається значення буде> = 0 тоді і тільки тоді, коли знайдено ключ». - Yoory N.


Для чого це варте, я провів тест, який порівнював 3 пропозиції щодо швидкості. Я генерував випадкові цілі числа, перетворив їх в String і додав їх до масиву. Я тоді шукав найвище можливе число / рядок, що було б найгіршим сценарієм для asList (). Contains ().

Використовуючи розмір масиву 10K, результати:

Сортування та пошук: 15
Двійковий пошук: 0
asList.contains: 0

При використанні масиву 100K результати, де:

Сортування та пошук: 156
Двійковий пошук: 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));
    }
}

46
2017-07-15 01:28



Я не розумію цей код. Ви сортуєте рядки масиву та використовуєте той самий (відсортований) масив у обох викликах до binarySearch. Як це може показати що-небудь, окрім оптимізації робочого часу на HotSpot? Те ж саме з asList.contains call. Ви створюєте список із сортованого масиву, а потім містить на ньому найвище значення. Звичайно, це займе час. Який сенс цього тесту? Не кажучи вже про неправильно написаний мікропоказник - Erik
Крім того, оскільки бінарний пошук може застосовуватися лише до відсортованого набору, сортування та пошук є єдиним можливим способом використання двійкового пошуку. - Erik
Сортування, можливо, вже було зроблено з ряду інших причин, наприклад, його можна було відсортувати за допомогою init і ніколи не змінювати. Там використовується при тестуванні часу пошуку самостійно. Однак, де це падає, він є меншим, ніж зоряним прикладом мікроелементів. Microbenchmarks, як відомо, важко отримати правильне уявлення в Java, і, наприклад, необхідно виконати тестовий код достатньо для того, щоб отримати оптимізацію хост-точки перед тим, як запустити фактичний тест, не кажучи вже про те, щоб керувати фактичним тестовим кодом більш, ніж одночасно з таймером. Приклади пасток - Thor84no
Цей тест недосконалий, оскільки він виконує всі 3 тести в той же Екземпляр JVM. Пізніші тести можуть скористатися попередніми розігріваннями кешу, JIT та ін - Steve Kuo
Цей тест насправді абсолютно не пов'язаний. Сортування і пошук є лінійної (n * log (n)) складністю, бінарний пошук логарифмічний, а ArrayUtils.contains, очевидно, є лінійним. Не варто порівнювати ці рішення, оскільки вони знаходяться в абсолютно різних ступенях складності. - dragn


Замість використання синтаксису ініціалізації швидкого масиву ви можете просто ініціалізувати його як список прямо зараз, використовуючи метод Arrays.asList, наприклад:

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

Тоді ви можете зробити (як і вище): STRINGS.contains("the string you want to find");


29
2018-01-20 13:58





За допомогою 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);
}

29
2018-03-13 14:53



Варто також відзначити примітивні спеціалізації. - skiwi
До того ж додати anyMatch JavaDoc стверджує, що це "...May not evaluate the predicate on all elements if not necessary for determining the result.", тому, можливо, не доведеться продовжувати обробку після пошуку відповідності. - mkobit