У меня есть String[]
со значениями, такими как:
public static final String[] VALUES = new String[] {"AB","BC","CD","AE"};
Учитывая String s
, есть ли хороший способ тестирования, VALUES
содержит ли s
?
У меня есть String[]
со значениями, такими как:
public static final String[] VALUES = new String[] {"AB","BC","CD","AE"};
Учитывая String s
, есть ли хороший способ тестирования, VALUES
содержит ли s
?
Ответы:
Arrays.asList(yourArray).contains(yourValue)
Предупреждение: это не работает для массивов примитивов (см. Комментарии).
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> ... {}}
.
Ссылочные массивы плохие. Для этого случая мы после набора. Начиная с Java SE 9 у нас есть Set.of
.
private static final Set<String> VALUES = Set.of(
"AB","BC","CD","AE"
);
«Учитывая строку s, есть ли хороший способ проверить, содержит ли VALUES s?»
VALUES.contains(s)
O (1).
Правильный тип , неизменен , O (1) и краткое . Прекрасный.*
Просто чтобы очистить код для начала. Мы (исправили):
public static final String[] VALUES = new String[] {"AB","BC","CD","AE"};
Это изменчивая статика, которую FindBugs скажет вам очень капризная. Не изменяйте статику и не позволяйте другому коду делать это тоже. Как минимум, поле должно быть приватным:
private static final String[] VALUES = new String[] {"AB","BC","CD","AE"};
(Обратите внимание, вы можете на самом деле отбросить new String[];
бит.)
Ссылочные массивы все еще плохи, и мы хотим установить:
private static final Set<String> VALUES = new HashSet<String>(Arrays.asList(
new String[] {"AB","BC","CD","AE"}
));
(Параноидальные люди, такие как я, могут чувствовать себя более непринужденно, если их обернуть Collections.unmodifiableSet
- тогда их даже можно будет обнародовать.)
(* Чтобы немного больше узнать о бренде, API коллекций, по-видимому, все еще не содержит неизменяемые типы коллекций, а синтаксис все еще слишком многословен, на мой вкус.)
Arrays.asList
)?
TreeSet
будет O(log n)
. HashSet
s масштабируются таким образом, чтобы среднее количество элементов в корзине было примерно постоянным. По крайней мере, для массивов до 2 ^ 30. Скажем, могут быть эффекты от, скажем, аппаратных кешей, которые анализ big-O игнорирует. Также предполагается, что хэш-функция работает эффективно.
Вы можете использовать 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.
}
Просто выполните это вручную:
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).
Четыре различных способа проверить, содержит ли массив значение
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
Если массив не отсортирован, вам придется перебирать все и вызывать равные для каждого.
Если массив отсортирован, вы можете выполнить бинарный поиск, он есть в классе Arrays .
Вообще говоря, если вы собираетесь делать много проверок членства, вы можете хранить все в наборе, а не в массиве.
Для чего это я запустил тест, сравнивая 3 предложения по скорости. Я сгенерировал случайные целые числа, преобразовал их в строку и добавил их в массив. Затем я искал максимально возможное число / строку, что было бы наихудшим сценарием для asList().contains()
.
При использовании размера массива 10K были получены следующие результаты:
Сортировка и поиск: 15 Двоичный поиск: 0 asList.contains: 0
При использовании массива 100K были получены следующие результаты:
Сортировка и поиск: 156 Двоичный поиск: 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 сразу же, используя метод 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."
так, поэтому может не потребоваться продолжать обработку после нахождения соответствия.
Вы можете использовать класс Arrays для выполнения двоичного поиска значения. Если ваш массив не отсортирован, вам придется использовать функции сортировки в том же классе, чтобы отсортировать массив, а затем выполнить поиск по нему.
ObStupidAnswer (но я думаю, что где-то здесь есть урок):
enum Values {
AB, BC, CD, AE
}
try {
Values.valueOf(s);
return true;
} catch (IllegalArgumentException exc) {
return false;
}
На самом деле, если вы используете HashSet <String>, как предложил Том Хоутин, вам не нужно беспокоиться о сортировке, и ваша скорость такая же, как при бинарном поиске в предварительно отсортированном массиве, возможно, даже быстрее.
Очевидно, все зависит от того, как настроен ваш код, но с того места, где я стою, порядок будет следующим:
На несортированном массиве:
В отсортированном массиве:
Так или иначе, 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");
Одно из возможных решений:
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;
Первый более читабелен, чем второй.
Использование простого цикла является наиболее эффективным способом сделать это.
boolean useLoop(String[] arr, String targetValue) {
for(String s: arr){
if(s.equals(targetValue))
return true;
}
return false;
}
Предоставлено Programcreek
В Java 8 используйте Streams.
List<String> myList =
Arrays.asList("a1", "a2", "b1", "c2", "c1");
myList
.stream()
.filter(s -> s.startsWith("c"))
.map(String::toUpperCase)
.sorted()
.forEach(System.out::println);
Для массивов ограниченной длины используйте следующее (как указано в 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);
TreeSet
? HashSet
быстрее (O (1)) и не требует упорядочения.
Попробуй это:
ArrayList<Integer> arrlist = new ArrayList<Integer>(8);
// use add() method to add elements in the list
arrlist.add(20);
arrlist.add(25);
arrlist.add(10);
arrlist.add(15);
boolean retval = arrlist.contains(10);
if (retval == true) {
System.out.println("10 is contained in the list");
}
else {
System.out.println("10 is not contained in the list");
}
Используйте следующее ( 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()
, которые были использованы в других местах.
Проверь это
String[] VALUES = new String[] {"AB","BC","CD","AE"};
String s;
for(int i=0; i< VALUES.length ; i++)
{
if ( VALUES[i].equals(s) )
{
// do your stuff
}
else{
//do your stuff
}
}
else
для каждого элемента, который не соответствует (поэтому, если вы ищете «AB» в этом массиве, он будет идти туда 3 раза, так как 3 значения не являются «AB» «).
Arrays.asList () -> тогда вызов метода contains () всегда будет работать, но алгоритм поиска намного лучше, так как вам не нужно создавать облегченную оболочку списка вокруг массива, что делает Arrays.asList () ,
public boolean findString(String[] strings, String desired){
for (String str : strings){
if (desired.equals(str)) {
return true;
}
}
return false; //if we get here… there is no desired String, return false.
}
Arrays.asList
это не O (n). Это просто легкая обертка. Посмотрите на реализацию.
Если вы не хотите, чтобы он был чувствительным к регистру
Arrays.stream(VALUES).anyMatch(s::equalsIgnoreCase);
использование Array.BinarySearch(array,obj)
для нахождения данного объекта в массиве или нет.
Пример:
if (Array.BinarySearch(str, i) > -1)` → true --exists
ложь - не существует
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.
Создайте логическое значение, изначально установленное в false. Запустите цикл, чтобы проверить каждое значение в массиве и сравнить со значением, которое вы проверяете. Если вы когда-нибудь получите совпадение, установите логическое значение в true и остановите цикл. Тогда утверждают, что логическое значение истинно.
Попробуйте использовать метод теста предикатов Java 8
Вот полный пример этого.
import java.util.Arrays;
import java.util.List;
import java.util.function.Predicate;
public class Test {
public static final List<String> VALUES = Arrays.asList("AA", "AB", "BC", "CD", "AE");
public static void main(String args[]) {
Predicate<String> containsLetterA = VALUES -> VALUES.contains("AB");
for (String i : VALUES) {
System.out.println(containsLetterA.test(i));
}
}
}
http://mytechnologythought.blogspot.com/2019/10/java-8-predicate-test-method-example.html
https://github.com/VipulGulhane1/java8/blob/master/Test.java
использование 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 );
…
Поскольку я имею дело с низкоуровневой Java, использующей примитивные типы byte и byte [], лучшее, что я получил на данный момент, - это bytes-java https://github.com/patrickfav/bytes-java, что кажется хорошей работой.
Вы можете проверить это двумя способами
A) Путем преобразования массива в строку и проверки необходимой строки методом .contains
String a=Arrays.toString(VALUES);
System.out.println(a.contains("AB"));
System.out.println(a.contains("BC"));
System.out.println(a.contains("CD"));
System.out.println(a.contains("AE"));
Б) это более эффективный метод
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));
}