У мене є 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"
);
"Дано 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 колекцій передбачувано все ще не вистачає незмінних типів колекцій, і синтаксис, на мій смак, все ще надто багатослівний.)
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) Використання набору:
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 пропозиції щодо швидкості. Я генерував випадкові цілі числа, перетворив їх у String і додав їх у масив. Потім я шукав максимально можливе число / рядок, який був би найгіршим сценарієм для asList().contains()
.
При використанні 10K розміру масиву результати були:
Сортування та пошук: 15 Двійковий пошук: 0 asList.міст: 0
При використанні масиву 100K результати були:
Сортування та пошук: 156 Двійковий пошук: 0 asList.міст: 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));
}
}
Замість того, щоб використовувати синтаксис швидкого масиву ініціалізації, ви можете просто ініціалізувати його як список безпосередньо аналогічним чином, використовуючи метод 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(...)
Для швидкої продуктивності, якщо ви неодноразово перевіряєте наявність більшого набору елементів
Масив - неправильна структура. Використовуйте a TreeSet
і додайте до нього кожен елемент. Він сортує елементи та має швидкий exist()
метод (двійковий пошук).
Якщо елементи реалізують Comparable
& ви хочете TreeSet
відсортувати відповідно:
ElementClass.compareTo()
метод повинен бути порівнянним з ElementClass.equals()
: див. Тріади, не показані для боротьби? (У наборі Java відсутній елемент)
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 () -> тоді виклик методу містить () завжди буде працювати, але алгоритм пошуку набагато кращий, оскільки вам не потрібно створювати легку обгортку списку навколо масиву, що і робить 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
false - не існує
Array.BinarySearch
і Array.FindIndex
є методами .NET і не існують на Java.
The array must be sorted prior to making this call. If it is not sorted, the results are undefined.
Створіть булевий початковий параметр 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 низького рівня з використанням байтів та байтів примітивних типів [], найкраще, що я отримав, - це від байтів-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));
}