Списочный массив ArrayList
Усвоив, что такое массивы, можно поближе изучить java.util.ArrayList — самый популярный вид списков. По названию пространства имён видно, что данный класс относится к Java.
ArrayList — автоматически расширяемый массив. Вы можете работать с массивом, но при этом не используются квадратные скобки.
Массивы имеют фиксированную длину, и после того как массив создан, он не может расти или уменьшаться. ArrayList может менять свой размер во время исполнения программы, при этом не обязательно указывать размерность при создании объекта. Кроме того, вы без проблем можете вставить новый элемент в середину коллекции. А также спокойно удалить элемент из любого места. Элементы ArrayList могут быть абсолютно любых типов в том числе и null. Это удобно, когда вы не знаете точного размера массива. Для сравнения — гостиница для котов имеет фиксированное число номеров, массив использовать можно. Вы владелец преуспевающей компании и число наёмных работников постоянно увеличивается, обычный массив создавать для учёта сотрудников нецелесообразно. В этом случае удобнее работать со списочным массивом. Иногда говорят, что ArrayList — это массив на стероидах (продвинутый).
Работать с ArrayList просто: создайте нужный объект, вставьте объект методом add(), обращайтесь к нему методом get(), используйте индексирование так же, как для массивов, но без квадратных скобок. ArrayList также содержит метод size(), который возвращает текущее количество элементов в массиве (напомню, что в обычном массиве используется свойство length).
Переменные принято называть во множественном числе.
Рассмотрим на примерах.
ArrayList catNames = new ArrayList(); catNames.add("Васька"); mResultEditText.setText(catnamesList.get(0));
Запускаем программу и видим, что в текстовом поле отобразилось имя кота Васьки. Что же произошло? Мы объявили экземпляр класса ArrayList под именем catNames и через метод add() добавили имя. Списочный массив стал содержать одну строку и мы можем в этом убедиться, когда выводим в текстовом поле первый элемент массива через индекс, равный 0.
Продолжим опыт. Перенесём объявление класса на уровень нашего основного класса и добавим через кнопку ещё два имени.
private ArrayList mCatNames = new ArrayList(); @Override protected void onCreate(Bundle savedInstanceState) < super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mButton = (Button) findViewById(R.id.buttonGetResult); mResultEditText = (EditText) findViewById(R.id.editText); mInfoTextView = (TextView) findViewById(R.id.textViewInfo); mCatNames.add("Васька"); mResultEditText.setText(mCatNames.get(0)); >public void onClick(View view)
Что теперь произошло? В методе onCreate() как прежде добавляется одно имя, которое выводится в текстовом поле. При нажатии на кнопку мы добавляем ещё два имени, а в текстовой метке выводим имя второго кота через метод catnamesList.get(1).
Хорошо, мы знаем, что добавили трёх котов и поэтому можем обращаться через индекс 0, 1 или 2. А если котов стало слишком много, и мы запутались в их количестве? Тогда нужно вызвать метод size(), который вернёт общее число элементов массива. В этом случае, чтобы получить имя последнего кота в массиве, нужно получить размер массива и отнять единицу.
mInfoTextView.setText(mCatNames.get(mCatNames.size() - 1));
Вроде бы всё замечательно. Но студия выводит предупреждение у кода метода add(). Почему?
Мы знаем, что у кота есть четыре лапы и хвост. Создадим отдельную переменную для количества лап и попробуем запихнуть их в массив имён. Выглядит как бред, но Java не ругается на наши действия. Вы можете через метод size() убедиться, что размер массива увеличился. Но при попытке вывести последний элемент получим ошибку.
public void onClick(View view) < mCatNames.add("Мурзик"); mCatNames.add("Рыжик"); int paws = 4; // четыре лапы mCatNames.add(paws); mInfoTextView.setText(mCatNames.get(mCatNames.size() - 1)); >
Чтобы вы не совершали подобных ошибок, был придуман следующий подход. Когда вы создаёте новый объект для массива, то в угловых скобках сразу указываете, какой тип собираетесь использовать.
ArrayList mCatNames = new ArrayList<>();
Как только вы исправите пример, то строчка mCatNames.add(paws); будет сразу подчёркнута красной линией. Java поняла, что мы хотим использовать в массиве только строки, а не числа. Поэтому, вы уже не совершите глупых ошибок. Удалите неправильную строку, остальное можно оставить без изменений.
private ArrayList mCatNames = new ArrayList(); @Override protected void onCreate(Bundle savedInstanceState) < super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mButton = findViewById(R.id.buttonGetResult); mResultEditText = findViewById(R.id.editText); mInfoTextView = findViewById(R.id.textViewInfo); mCatNames.add("Васька"); mResultEditText.setText(mCatNames.get(0)); >public void onClick(View view) < mCatNames.add("Мурзик"); mCatNames.add("Рыжик"); // добавим ещё одного наглого кота. Он очень настаивал mCatNames.add("Барсик"); // выводим имя последнего кота из массива и размер массива mInfoTextView.setText(mCatNames.get(mCatNames.size() - 1) + " Размер массива " + mCatNames.size()); >
Теперь студия не ругается, и мы можем свернуться калачиком и поспать.
Такая форма записи с угловыми скобками говорит о том, что мы использовали generic-класс (дженерик или обобщение) с типизированными параметрами.
В Java 7 появилась укороченная запись, называемая ромбовидной. Вы можете опустить параметр с правой стороны выражения.
ArrayList mCatNames = new ArrayList<>();
В обобщениях можно использовать только объекты классов. Поэтому запись ArrayList не прокатит. В таких случаях следует использовать класс Integer: ArrayList . Но с другой стороны это чревато большим расходом памяти.
Если у вас есть собственный класс, то он используется таким же образом, только с использованием ключевого слова new.
ArrayList cats = new ArrayList<>(); cats.add(new Cat("Васька")); cats.add(new Cat("Барсик"));
Метод add()
Метод add() самый популярный и не требует особых объяснений. Только не забывайте, что существует перегруженная версия метода, позволяющая вставлять элемент в нужную позицию.
cats.add(2, new Cat("Рыжик"));
Следует быть осторожным, чтобы ненароком не вставить в несуществующую позицию. По возможности, избегайте операций вставки в середину коллекции. Ведь системе приходится заново пересчитывать индексы элементов.
Методы ensureCapacity() и trimToSize()
Если заранее известно, сколько элементов следует хранить, то перед заполнением массива вызовите метод ensureCapacity():
mCatNames.ensureCapacity(100);
Первоначальную ёмкость можно задать и в конструкторе в качестве параметра.
ArrayList mCatNames = new ArrayList<>(100);
Если вы уверены, что списочный массив будет иметь постоянный размер, то можете использовать метод trimToSize(). Это может способствовать рациональному использованию памяти.
Метод indexOf()
Предположим, мы внимательно следим за Рыжиком. Когда он был последним, то его легко было вычислить. Зная размер массива, мы вычитали единицу и получали к нему доступ. Но потом мы стали добавлять в массив других котов и уже не сможем понять, где теперь наш Рыжик. Но выход всегда есть. Существует метод indexOf(), который ищет подходящий элемент и выводит его индекс.
int index = mCatNames.indexOf("Рыжик"); // выводим имя кота и его номер в массиве mInfoTextView.setText("Рыжик числится под номером " + index);
Не забываем, что отсчёт массива идёт с 0, если индекс равен 2, значит он является третим в массиве.
Просмотр всех элементов через цикл
Чтобы вывести всех усатых-полосатых на чистую воду, используем цикл for:
String catName = ""; for (int i = 0; i < mCatNames.size(); i++) < catName = catName + mCatNames.get(i) + " "; >mInfoTextView.setText("Все коты: " + catName);
Или укороченная запись:
String catName = ""; for (String name : mCatNames) < catName = catName + name + " "; >mInfoTextView.setText("Все коты: " + catName);
Метод contains()
Чтобы узнать, есть в массиве какой-либо элемент, можно воспользоваться методом contains(), который вернёт true или false:
mInfoTextView.setText(mCatNames.contains("Бобик") + "");
Понятно, что в нашем массиве никаких бобиков и барбосов быть не может, поэтому появится надпись false.
Метод remove() — удаление элемента
Для удаления элемента из массива используется метод remove(). Можно удалять по индексу или по объекту:
mCatNames.remove(0); // удаляем по индексу mCatNames.remove("Васька"); // удаляем по объекту
Элементы, следующие после удалённого элемента, сдвигаются влево, а размер списочного массива уменьшается на единицу.
Метод removeAll() удаляет сразу все элементы. Но лучше использовать метод clear().
Метод removeIf() — удаление элемента по предикату (Java 8)
Раньше, если нужно было удалить элемент из списка по условию, приходилось проходить в цикле по всем элементам и сравнивать их с условием. В Java 8 появился новый метод removeIf(), позволяющий упростить код. Метод использует предикат — вы указываете условие, если оно выполняется, то происходит удаление элемента из списка.
ArrayList numList = new ArrayList<>(); numList.add(51); numList.add(14); numList.add(11); numList.add(12); numList.add(31); numList.add(21); System.out.println("Оригинал: " + numList.toString()); // удаляем элементы, которые больше 10 и меньше 20 numList.removeIf(i -> (i > 10 && i < 20)); System.out.println("Новый список: " + numList.toString()); // Оригинал: [51, 14, 11, 12, 31, 21] // Новый список: [51, 31, 21]
Метод set() - замена элемента
Чтобы заменить элемент в массиве, нужно использовать метод set() с указанием индекса и новым значением. Предположим, вы обнаружили, что у вас не кот Мурзик, а кошка Мурка. Нет проблем.
mCatNames.add("Васька"); mCatNames.add("Мурзик"); mCatNames.add("Рыжик"); mCatNames.set(1, "Мурка"); mInfoTextView.setText(mCatNames.get(1) + "");
Метод clear() - очистка массива
Для очистки массива используется метод clear():
mCatNames.clear();
Метод работает гораздо быстрее похожего метода removeAll().
Метод toArray() - конвертируем в обычный массив
Также можно сконвертировать из нашего списка в обычный массив и выполнить другие операции. Читайте документацию.
ArrayList days = new ArrayList<>(); days.add("Monday"); days.add("Tuesday"); days.add("Wednesday"); days.add("Thursday"); days.add("Friday"); days.add("Saturday"); days.add("Sunday"); String[] daysArray = days.toArray(new String[days.size()]); System.out.println("Массив: " + Arrays.toString(daysArray));
Конвертация в массив может понадобится для ускорения некоторых операций, передачи массива в качестве параметра методам, которые требуют именно массив и другие причины.
Можно было реализовать эту задачу самостоятельно - создать пустой массив, в цикле пройтись по элементам ArrayList и поместить каждый элемент в массив. Важно только проследить за размером массива, который должен совпасть с размером списка.
ArrayList days = new ArrayList<>(); days.add("Monday"); days.add("Tuesday"); days.add("Wednesday"); days.add("Thursday"); days.add("Friday"); days.add("Saturday"); days.add("Sunday"); String[] daysArray = new String[days.size()]; for (int i = 0; i < days.size(); i++) < daysArray[i] = days.get(i); >System.out.println("Массив: " + Arrays.toString(daysArray));
В Java 8 появился ещё один вариант через Stream.
ArrayList days = new ArrayList<>(); days.add("Monday"); days.add("Tuesday"); days.add("Wednesday"); days.add("Thursday"); days.add("Friday"); days.add("Saturday"); days.add("Sunday"); String[] daysArray = days.stream().toArray(String[]::new); System.out.println("Массив: " + Arrays.toString(daysArray));
Сколько раз совпадают элементы
В списочном массиве значения вполне могут совпадать. Например, среди котов попадаются однофамильцы и мы их спокойно можем запихнуть в ArrayList. Но сколько раз повторяются одинаковые элементы?
ArrayList cats = new ArrayList<>(); cats.add("Мурзик"); cats.add("Васька"); cats.add("Мурзик"); int count = Collections.frequency(cats, "Мурзик"); // получим результат 2 mInfoTextView.setText(String.valueOf(count)); // выводим результат в TextView
Интерфейс List
java.util.List является интерфейсом и его можно использовать вместо ArrayList следующим образом:
List catnamesList = new ArrayList();
Или укороченный вариант для Java 7:
List catnamesList = new ArrayList<>();
Как видите, мы заменили ArrayList на List, но при этом в объявлении оставили new ArrayList(). Всё остальное остаётся без изменений. Кстати, этот способ является рекомендуемым. Но иногда он может не подойти.
Контейнеры List гарантируют определённый порядок следования элементов. Интерфейс List дополняет Collection несколькими методами, обеспечивающими вставку и удаление элементов в середине списка.
Существует две основные разновидности List:
- Базовый контейнер ArrayList, оптимизированный для произвольного доступа к элементам, но с относительно медленными операциями вставки/удаления элементов в середине списка.
- Контейнер LinkedList, оптимизированный для последовательного доступа, с быстрыми операциями вставки/удаления в середине списка. Произвольный доступ к элементам LinkedList выполняется относительно медленно, но по широте возможностей превосходит ArrayList.
В отличие от массива контейнер List позволяет добавлять и удалять элементы после создания, а также изменяет свои размеры.
Метод contains() проверяет, присутствует ли объект в списке. Чтобы удалить объект, передайте ссылку на него методу remove(). Кроме того, если у вас имеется ссылка на объект, вы можете определить индекс объекта в List при помощи метода indexOf().
Сам List реализует более общий интерфейс коллекции Collection и можно было даже написать:
Collection mCatNames = new ArrayList();
Но у Collection нет методов set() и get(), поэтому работать с таким интерфейсом не очень удобно.
Для создания массива можно не только добавлять по одному объекту через метод add(), но и сразу массив через метод Arrays.asList().
Оставим пока в покое котов и создадим массив из объектов Integer.
List numbers = Arrays.asList(1, 2, 5, 9, 11); mInfoTextView.setText(numbers.get(2) + ""); // выводит число 5
Но у данного способа есть недостаток. Если вы определили массив таким образом, то уже не можете вставлять или удалять другой элемент (методы add() и delete()), хотя при этом можете изменять существующий элемент.
List numbers = Arrays.asList(1, 2, 5, 9, 11); numbers.set(2, 33); // так можно //numbers.add(34); // нельзя, ошибка во время исполнения mInfoTextView.setText(numbers.get(2) + "");
В Android 11 (R) обещают добавить несколько перегруженных версий метода of(), которые являются частью Java 8.
Заключение
С ArrayList работать проще и удобнее, чем с массивами. Можно без проблем добавлять новые элементы, в том числе и в середину листа. А в случае использования обычного массива вам придётся заново выделять память и перезаписывать элементы, так как размер массива поменять нельзя, после того как была выделена память.
Работа с массивом быстрее и можно использовать массив, если точно знаете заранее размер массива и вам не придётся его динамически менять, делать вставки и т.д.
Структура данных в картинках
Теперь, когда вы получили представление об ArrayList, заглянем за кулисы и посмотрим, как данные хранятся в этом объекте. Источник
ArrayList list = new ArrayList();
Только что созданный объект list содержит свойства elementData и size.
Хранилище значений elementData есть ни что иное как массив определенного типа (указанного в generic), в нашем случае String[]. Если вызывается конструктор без параметров, то по умолчанию будет создан массив из 10-ти элементов типа Object (с приведением к типу, разумеется).
elementData = (E[]) new Object[10];

Добавим новый элемент:
list.add("0");

Внутри метода add(value) происходят следующие вещи:
1) проверяется, достаточно ли места в массиве для вставки нового элемента;
ensureCapacity(size + 1);
2) добавляется элемент в конец (согласно значению size) массива.
elementData[size++] = element;
Если места в массиве не достаточно, новая ёмкость рассчитывается по формуле (oldCapacity * 3) / 2 + 1. Второй момент это копирование элементов. Оно осуществляется с помощью native-метода System.arraycopy(), который написан не на Java.
// newCapacity - новое значение емкости elementData = (E[])new Object[newCapacity]; // oldData - временное хранилище текущего массива с данными System.arraycopy(oldData, 0, elementData, 0, size);
Ниже продемонстрирован цикл, поочередно добавляющий 15 элементов:
list.add("1");

Продолжаем добавлять 2, 3, 4, .
list.add("9");

list.add("10");
При добавлении 11-го элемента, проверка показывает что места в массиве нет. Соответственно создается новый массив и вызывается System.arraycopy().

После этого добавление элементов продолжается.

Рассмотрим добавление в «середину» списка.
list.add(5, "100");
Добавление элемента на позицию с определенным индексом происходит в три этапа:
1) проверяется, достаточно ли места в массиве для вставки нового элемента;
ensureCapacity(size+1);
2) подготавливается место для нового элемента с помощью System.arraycopy();
System.arraycopy(elementData, index, elementData, index + 1, size - index);

3) перезаписывается значение у элемента с указанным индексом.
elementData[index] = element; size++;

Как можно догадаться, в случаях, когда происходит вставка элемента по индексу и при этом в вашем массиве нет свободных мест, то вызов System.arraycopy() случится дважды: первый в ensureCapacity(), второй в самом методе add(index, value), что явно скажется на скорости всей операции добавления.
В случаях, когда в исходный список необходимо добавить другую коллекцию, да еще и в «середину», стоит использовать метод addAll(index, Collection). И хотя, данный метод скорее всего вызовет System.arraycopy() три раза, в итоге это будет гораздо быстрее поэлементного добавления.
Удалять элементы можно двумя способами:
— по индексу remove(index)
— по значению remove(value)
С удалением элемента по индексу всё достаточно просто:
list.remove(5);
Сначала определяется какое количество элементов надо скопировать:
int numMoved = size - index - 1;
Затем копируем элементы используя System.arraycopy():
System.arraycopy(elementData, index + 1, elementData, index, numMoved);
Уменьшаем размер массива и забываем про последний элемент:
elementData[--size] = null; // Let gc do its work
При удалении по значению, в цикле просматриваются все элементы списка, до тех пор пока не будет найдено соответствие. Удален будет лишь первый найденный элемент.
При удалении элементов текущая величина capacity не уменьшается, что может привести к своеобразным утечкам памяти. Поэтому не стоит пренебрегать методом trimToSize().
Объединяем два ArrayList
С помощью библиотеки Apache Commons Collections можно объединить два ArrayList.
List listA = new ArrayList(); listA.add("Васька"); listA.add("Барсик"); listA.add("Мурзик"); List listB = new ArrayList(); listB.add("Пушок"); listB.add("Снежок"); listB.add("Рыжик"); // объединяем два списочных массива List listAB = ListUtils.union(listA, listB); System.out.println("listA : " + listA); System.out.println("listB : " + listB); System.out.println("listAB : " + listAB);
Сортировка
Сортировать элементы можно при помощи метода Collections.sort().
List items = new ArrayList<>(); items.add("d"); items.add("c"); items.add("b"); items.add("a"); Collections.sort(items); System.out.println(items.toString());
Интерфейс ListIterator
На практике он мне не встречался. Позволяет проходить по всем элементам вперёд или назад. Для этого он проверяет, есть ли следующий/предыдущий элемент после текущего.
Выводим все элементы от начала до конца, а потом в обратном направлении.
ArrayList numbers = new ArrayList<>(Arrays.asList(1, 2, 3, 4, 5)); ListIterator iterator = numbers.listIterator(); System.out.println("Iterating in forward direction: "); while (iterator.hasNext()) < System.out.println(iterator.next()); >System.out.println(); System.out.println("Iterating in backward direction: "); while (iterator.hasPrevious())
Проверка наличия элемента в массиве в языке программирования Java
Важным аспектом программирования на Java является умение работать с массивами. Массивы используются для хранения набора значений одного типа. Нередко возникает необходимость проверить, содержит ли массив определенное значение. Рассмотрим пример:
String[] fruits = new String[] ;
Предположим, что необходимо проверить, содержит ли данный массив строк значение «Cherry».
Для этого в Java предусмотрено несколько способов.
Использование цикла for-each
Один из наиболее простых способов — это применение цикла for-each для обхода каждого элемента массива и проверки на равенство с искомым значением.
String targetValue = "Cherry"; for(String s: fruits) < if(s.equals(targetValue)) < System.out.println("Array contains the target value"); break; >>
Использование Java 8 Stream API
В Java 8 был введен Stream API, который предоставляет более удобные и компактные способы работы с коллекциями. Для проверки наличия элемента в массиве можно использовать методы stream() и anyMatch() .
boolean isPresent = Arrays.stream(fruits) .anyMatch(s -> s.equals(targetValue)); System.out.println(isPresent ? "Array contains the target value" : "Array doesn't contain the target value");
Использование класса Arrays
Класс Arrays предоставляет набор статических методов для работы с массивами. Один из них — asList() , который преобразует массив в список. Затем можно использовать метод contains() для проверки наличия элемента.
boolean isPresent = Arrays.asList(fruits).contains(targetValue); System.out.println(isPresent ? "Array contains the target value" : "Array doesn't contain the target value");
Это лишь некоторые из способов проверки наличия элемента в массиве в Java. Выбор метода зависит от конкретных требований и предпочтений.
Проверка наличия элемента в массиве строк
Является ли этот метод оптимальным, или же это "велосипед", и существует более оптимальное решение этой задачи?
Отслеживать
19.1k 6 6 золотых знаков 30 30 серебряных знаков 44 44 бронзовых знака
задан 13 янв 2017 в 22:09
513 1 1 золотой знак 5 5 серебряных знаков 19 19 бронзовых знаков
Массив сортирован? Можно ли его отсортировать?
13 янв 2017 в 22:21
Массив не отсортирован, порядок его элементов не имеет значения
14 янв 2017 в 14:06
Юзайте, то что написали, это нормальное решение, для массива из <= 15 элементов.
14 янв 2017 в 19:03
4 ответа 4
Сортировка: Сброс на вариант по умолчанию
Если не касаться вопроса сортировки, то более короткой формой будет
return Arrays.asList(massStringA).contains(s);
(заметьте, Arrays.asList() не создаёт копию массива, а использует оригинал, так что это не удваивает расход памяти).
Отслеживать
ответ дан 13 янв 2017 в 22:31
2,181 15 15 серебряных знаков 21 21 бронзовый знак
Если массив может быть отсортирован, то тогда можно ускорить механизм поиска.
String[] massStringA = . ; // массив будет изменен! Arrays.sort(massStringA); if(Arrays.binarySearch(massStringA, a) >= 0) < // строка найдена >;
Если массив нельзя изменять и используется Java 8, то можно применить Stream
if(Arrays.stream(massStringA).anyMatch(s -> s.equals(a))) < // строка найдена >
Отслеживать
ответ дан 13 янв 2017 в 23:54
Mikhail Vaysman Mikhail Vaysman
14.2k 1 1 золотой знак 21 21 серебряный знак 31 31 бронзовый знак
Более оптимальное решение - скопировать String[] в HashSet , после чего использовать метод contains у HashSet .
Сделал искусственный пример. Возможно, на реальных данных результаты будут отличаться.
private static final int STRINGS_COUNT = 100 * 1000, TESTS_COUNT = 100 * 1000; private static final HashSet hashSet = new HashSet<>(); private static final String[] massStringA = new String[STRINGS_COUNT]; public static void main(String[] args) < for (int i = 0; i < STRINGS_COUNT; i++) < massStringA[i] = createString(i); >long startTime = System.currentTimeMillis(); hashSet.addAll(Arrays.asList(massStringA)); System.out.println("Copy time: " + (System.currentTimeMillis() - startTime) + "ms"); Random rand = new Random(); String[] testStrings = new String[TESTS_COUNT]; for (int i = 0; i < TESTS_COUNT; i++) < int randValue = rand.nextInt(STRINGS_COUNT * 10); testStrings[i] = createString(randValue); >startTime = System.currentTimeMillis(); int matches = 0; for (int i = 0; i < TESTS_COUNT; i++) < if (existA(testStrings[i])) < matches++; >> System.out.println("Array search time: " + (System.currentTimeMillis() - startTime) + "ms, matches: " + matches); startTime = System.currentTimeMillis(); matches = 0; for (int i = 0; i < TESTS_COUNT; i++) < if (Arrays.asList(massStringA).contains(testStrings[i])) < matches++; >> System.out.println("Arrays.asList search time: " + (System.currentTimeMillis() - startTime) + "ms, matches: " + matches); startTime = System.currentTimeMillis(); matches = 0; for (int i = 0; i < TESTS_COUNT; i++) < if (hashSet.contains(testStrings[i])) < matches++; >> System.out.println("HashSet search time: " + (System.currentTimeMillis() - startTime) + "ms, matches: " + matches); > private static String createString(int number) < int value = number; StringBuilder sb = new StringBuilder(); while (value >0) < sb.append((char)(value % 80 + 47)); value /= 80; >return sb.toString(); > private static boolean existA(String a) < for (String s : massStringA) < if (a.equals(s)) < return true; >> return false; >
Для 100 тысяч тестов при 100 тысячах строк результаты такие:
Copy time: 16ms Array search time: 69762ms, matches: 9858 Arrays.asList search time: 73248ms, matches: 9858 HashSet search time: 14ms, matches: 9858
Для миллиона тестов при 10 тысячах строк:
Copy time: 3ms Array search time: 17775ms, matches: 99845 Arrays.asList search time: 17537ms, matches: 99845 HashSet search time: 26ms, matches: 99845
Rukovodstvo
статьи и идеи для разработчиков программного обеспечения и веб-разработчиков.
Java: проверьте, содержит ли массив значение или элемент
Введение В Java или на любом другом языке программирования обычно проверяют, содержит ли массив значение. Это одна из вещей, которую обычно усваивают новички, и в целом это полезно знать. В этой статье мы рассмотрим, как проверить, содержит ли массив значение или элемент в Java. * Arrays.asList (). Contains () * Использование цикла for * Collections.binarySearch () * API потока Java 8 * Apache Commons - ArrayUtils Arrays.asList (). Contains () T
Время чтения: 4 мин.
Вступление
Будь то Java или любой другой язык программирования, обычно проверяют, содержит ли массив значение. Это одна из вещей, которую обычно усваивают новички, и в целом это полезно знать.
В этой статье мы рассмотрим, как проверить, содержит ли массив значение или элемент в Java .
- Arrays.asList (). Contains ()
- Использование цикла for
- Collections.binarySearch ()
- Java 8 Stream API
- Apache Commons - ArrayUtils
Arrays.asList (). Contains ()
Это, пожалуй, самый распространенный способ решения этой проблемы просто потому, что он работает очень хорошо и его легко реализовать.
Сначала мы конвертируем массив в ArrayList . Существуют различные способы преобразования массива Java в ArrayList , однако мы будем использовать наиболее широко используемый подход.
Затем мы можем использовать метод contains() для результирующего ArrayList , который возвращает логическое значение, указывающее, содержит ли список переданный нам элемент или нет.
Массив Integer типа:
Integer[] intArray = new Integer[]; String[] nameArray = new String[]; List intList = new ArrayList<>(Arrays.asList(intArray)); List nameList = new ArrayList<>(Arrays.asList(nameArray)); System.out.println(intList.contains(12)); System.out.println(nameList.contains("John"));
Выполнение этого кода приводит к:
false true
Использование цикла for
Более простой и ручной подход к решению проблемы - использование цикла for В худшем случае он выполнит итерацию по всему массиву один раз, проверяя, присутствует ли элемент.
Начнем сначала с примитивных целых чисел:
int[] intArray = new int[]; boolean found = false; int searchedValue = 2; for(int x : intArray) < if(x == searchedValue)< found = true; break; >> System.out.println(found);
Для found переменной изначально установлено значение false потому что единственный способ вернуть true это найти элемент и явно присвоить новое значение логическому элементу. Здесь мы просто сравниваем каждый элемент массива со значением, которое ищем, и возвращаем true если они совпадают:
true
Для строк и настраиваемых объектов, которые могут быть в вашем коде, вы должны использовать другой оператор сравнения. Предполагая, что вы действительно переопределили метод equals() , вы можете использовать его, чтобы проверить, равен ли объект другому, возвращая true если они:
String[] stringArray = new String[]; boolean found = false; String searchedValue = "Michael"; for(String x : stringArray) < if(x.equals(searchedValue))< found = true; break; >> System.out.println(found);
Выполнение этого кода приведет к:
false
Collections.binarySearch ()
Кроме того, мы можем найти конкретное значение, используя встроенный метод binarySearch() из класса Collections Проблема с двоичным поиском в том, что он требует сортировки нашего массива. Если наш массив отсортирован , хотя, binarySearch() превосходит как Arrays.asList().contains() и для петли подходов.
Если он не отсортирован, дополнительное время, необходимое для сортировки массива, может сделать этот подход менее выгодным, в зависимости от размера массива и алгоритма сортировки, используемого для его сортировки.
binarySearch() имеет много перегруженных вариантов в зависимости от используемых типов и наших собственных требований, но наиболее общий из них:
public static int binarySearch(Object[] a, Object[] key)
Где a представляет массив, и key указанное значение, которое мы ищем.
Теперь возвращаемое значение может немного сбивать с толку, поэтому лучше иметь в виду официальную документацию Oracle:
Возвращаемое значение этого метода - индекс искомого ключа, если он содержится в массиве; в противном случае (- ( точка вставки ) - 1), где точка вставки определяется как точка, в которой ключ будет вставлен в массив: индекс первого элемента больше, чем ключ, или a.length если все элементы в массив меньше указанного ключа.
Давайте попробуем это:
Integer[] intArray = new Integer[]; String[] nameArray = new String[]; // Array is already sorted lexicographically List intList = new ArrayList<>(Arrays.asList(intArray)); List nameList = new ArrayList<>(Arrays.asList(nameArray)); System.out.println(Collections.binarySearch(intList, 2)); System.out.println(Collections.binarySearch(nameList, "Robin"));
Первый элемент находится в позиции 1 . Второй элемент не найден и будет вставлен в позицию 5 - в конец массива. Возвращаемое значение -(insertion point)-1 , поэтому возвращаемое значение оказывается -6 .
Если значение больше или равно 0 , массив содержит элемент, в противном случае он не содержит его.
Java 8 Stream API
Java 8 Stream API очень универсален и предлагает краткие решения различных задач, связанных с обработкой коллекций объектов. Для большинства задач использование Streams является естественным и интуитивно понятным.
Давайте посмотрим, как мы можем использовать Stream API, чтобы проверить, содержит ли массив целое число:
Integer[] arr = new Integer[]; System.out.println(Arrays.stream(arr).anyMatch(x -> x == 3));
true
И чтобы сделать это со строками или настраиваемыми объектами:
String[] arr = new String[]; String searchString = "Michael"; boolean doesContain = Arrays.stream(arr) .anyMatch(x -> x.equals(searchString)); System.out.println(doesContain);
Или вы можете сделать это короче, используя ссылку на метод:
boolean doesContain = Arrays.stream(arr) .anyMatch(searchString::equals); System.out.println(doesContain);
Оба они выведут:
false
Apache Commons - ArrayUtils
Библиотека Apache Commons предоставляет множество новых интерфейсов, реализаций и классов, расширяющих базовую платформу Java Framework, и присутствует во многих проектах.
Класс ArrayUtils представляет множество методов для управления массивами, включая метод contains() :
Integer[] intArray = new Integer[]; String[] nameArray = new String[]; System.out.println(ArrayUtils.contains(intArray, 3)); System.out.println(ArrayUtils.contains(nameArray, "John"));
true true
Заключение
В этой статье мы рассмотрели несколько способов проверить, содержит ли массив в Java определенный элемент или значение. Мы рассмотрели преобразование массива в список и вызов contains() с использованием цикла for, Java 8 Stream API, а также Apache Commons.
Licensed under CC BY-NC-SA 4.0