Как удалить объекты из массива в Java?
дан массив n объекты, скажем, это массив строк, и имеет следующие значения:
foo[0] = "a";
foo[1] = "cc";
foo[2] = "a";
foo[3] = "dd";
что мне нужно сделать, чтобы удалить / удалить все строки / объекты, равные "а" в массиве?
18 ответов:
[если вам нужен готовый к использованию код, прокрутите до моего "Edit3" (после разреза). Остальное здесь для потомков.]
воплощение идея мусорщика:
List<String> list = new ArrayList<String>(Arrays.asList(array)); list.removeAll(Arrays.asList("a")); array = list.toArray(array);
Edit: теперь я использую
Arrays.asList
вместоCollections.singleton
: синглтон ограничен одной записью, тогда какasList
подход позволяет добавлять другие строки для фильтрации позже:Arrays.asList("a", "b", "c")
.Edit2: приведенный выше подход сохраняет тот же массив (так что массив по-прежнему тот же length); элемент после последнего имеет значение null. Если вы хотите новая массив размера точно так, как требуется, используйте этот код:
array = list.toArray(new String[0]);
Edit3: если вы часто используете этот код в одном классе, вы можете добавить его в свой класс:
private static final String[] EMPTY_STRING_ARRAY = new String[0];
тогда функция становится:
List<String> list = new ArrayList<>(); Collections.addAll(list, array); list.removeAll(Arrays.asList("a")); array = list.toArray(EMPTY_STRING_ARRAY);
это прекратит засорять вашу кучу бесполезными пустыми строковыми массивами, которые в противном случае были бы
new
ed каждый время вызова вашей функции.предложение циника (см. комментарии) также поможет с мусором кучи, и для справедливости я должен упомянуть об этом:
array = list.toArray(new String[list.size()]);
Я предпочитаю мой подход, потому что это может быть проще получить явный размер неправильно (например, вызов
size()
в том списке).
альтернатива в Java 8:
String[] filteredArray = Arrays.stream(array) .filter(e -> !e.equals(foo)).toArray(String[]::new);
сделать
List
из массива сArrays.asList()
, а вызовremove()
на всех соответствующих элементах. Тогда звонитеtoArray()
в "списке", чтобы снова вернуться в массив.не очень эффективно, но если вы инкапсулируете его правильно, вы всегда можете сделать что-то быстрее позже.
вы всегда можете это сделать:
int i, j; for (i = j = 0; j < foo.length; ++j) if (!"a".equals(foo[j])) foo[i++] = foo[j]; foo = Arrays.copyOf(foo, i);
вы можете использовать внешние библиотеки:
org.apache.commons.lang.ArrayUtils.remove(java.lang.Object[] array, int index)
Он находится в проекте Apache Commons Lang http://commons.apache.org/lang/
см. код ниже
ArrayList<String> a = new ArrayList<>(Arrays.asList(strings)); a.remove(i); strings = new String[a.size()]; a.toArray(strings);
Если вам нужно удалить несколько элементов из массива без преобразования его в
List
ни создание дополнительного массива, вы можете сделать это в O (n) не зависит от количества элементов для удаления.здесь
a
- это исходный массив,int... r
различные упорядоченные индексы (позиции) элементов для удаления:public int removeItems(Object[] a, int... r) { int shift = 0; for (int i = 0; i < a.length; i++) { if (shift < r.length && i == r[shift]) // i-th item needs to be removed shift++; // increment `shift` else a[i - shift] = a[i]; // move i-th item `shift` positions left } for (int i = a.length - shift; i < a.length; i++) a[i] = null; // replace remaining items by nulls return a.length - shift; // return new "length" }
небольшой тестирование:
String[] a = {"0", "1", "2", "3", "4"}; removeItems(a, 0, 3, 4); // remove 0-th, 3-rd and 4-th items System.out.println(Arrays.asList(a)); // [1, 2, null, null, null]
в вашей задаче вы можете сначала сканировать массив, чтобы собрать позиции "a", а затем вызвать
removeItems()
.
что-то о том, чтобы сделать список из него, а затем удалить, а затем вернуться к массиву, кажется мне неправильным. Не проверял, но я думаю, что следующий будет лучше. Да, я, вероятно, неоправданно предварительно оптимизирую.
boolean [] deleteItem = new boolean[arr.length]; int size=0; for(int i=0;i<arr.length;i==){ if(arr[i].equals("a")){ deleteItem[i]=true; } else{ deleteItem[i]=false; size++; } } String[] newArr=new String[size]; int index=0; for(int i=0;i<arr.length;i++){ if(!deleteItem[i]){ newArr[index++]=arr[i]; } }
Я понимаю, что это очень старый пост, но некоторые ответы здесь помогли мне, так что вот мои два пенса' полпенни стоит!
Я изо всех сил пытался заставить это работать довольно долго, прежде чем ветвиться, что массив, в который я пишу, должен быть изменен, если только изменения, внесенные в
ArrayList
оставьте размер списка без изменений.если
ArrayList
то, что вы изменяете, заканчивается большим или меньшим количеством элементов, чем это началось, строкаList.toArray()
будет вызвать исключение, так что вам нужно что-то вродеList.toArray(new String[] {})
илиList.toArray(new String[0])
для того, чтобы создать массив с новым (правильным) размер.Звучит очевидно теперь, когда я это знаю. Не так очевидно для новичка Android / Java, который сталкивается с новыми и незнакомыми конструкциями кода и не очевиден из некоторых предыдущих сообщений здесь, поэтому просто хотел сделать этот момент действительно ясным для кого-то еще, почесывая голову в течение нескольких часов, как я!
EDIT:
точка с нулями в массиве была очищена. Извините за мои комментарии.
Оригинал:
Эм... линия
array = list.toArray(array);
заменяет все пробелы в массиве, где был удален элемент с null. Это может быть опасно, потому что элементы удаляются, но длина массива остается неизменным!
если вы хотите избежать этого, используйте новый массив в качестве параметра для toArray (). Если вы не хотите использовать removeAll, набор будет альтернативой:
String[] array = new String[] { "a", "bc" ,"dc" ,"a", "ef" }; System.out.println(Arrays.toString(array)); Set<String> asSet = new HashSet<String>(Arrays.asList(array)); asSet.remove("a"); array = asSet.toArray(new String[] {}); System.out.println(Arrays.toString(array));
выдает:
[a, bc, dc, a, ef] [dc, ef, bc]
, где в качестве текущего принимается ответ от Криса прошлый молодой выходы:
[a, bc, dc, a, ef] [bc, dc, ef, null, ef]
код
String[] array = new String[] { "a", "bc" ,"dc" ,"a", "ef" }; System.out.println(Arrays.toString(array)); List<String> list = new ArrayList<String>(Arrays.asList(array)); list.removeAll(Arrays.asList("a")); array = list.toArray(array); System.out.println(Arrays.toString(array));
без какого-либо значения null оставил.
мой небольшой вклад в эту проблему.
public class DeleteElementFromArray { public static String foo[] = {"a","cc","a","dd"}; public static String search = "a"; public static void main(String[] args) { long stop = 0; long time = 0; long start = 0; System.out.println("Searched value in Array is: "+search); System.out.println("foo length before is: "+foo.length); for(int i=0;i<foo.length;i++){ System.out.println("foo["+i+"] = "+foo[i]);} System.out.println("=============================================================="); start = System.nanoTime(); foo = removeElementfromArray(search, foo); stop = System.nanoTime(); time = stop - start; System.out.println("Equal search took in nano seconds = "+time); System.out.println("=========================================================="); for(int i=0;i<foo.length;i++){ System.out.println("foo["+i+"] = "+foo[i]);} } public static String[] removeElementfromArray( String toSearchfor, String arr[] ){ int i = 0; int t = 0; String tmp1[] = new String[arr.length]; for(;i<arr.length;i++){ if(arr[i] == toSearchfor){ i++; } tmp1[t] = arr[i]; t++; } String tmp2[] = new String[arr.length-t]; System.arraycopy(tmp1, 0, tmp2, 0, tmp2.length); arr = tmp2; tmp1 = null; tmp2 = null; return arr; }
}
здесь много ответов-проблема, как я вижу, заключается в том, что вы не сказали, почему вы используете массив вместо коллекции, поэтому позвольте мне предложить пару причин и какие решения будут применяться (большинство решений уже были даны ответы на другие вопросы здесь, поэтому я не буду вдаваться в подробности):
причина: Вы не знали, что пакет коллекции существует или не доверяли ему
решение: используйте коллекцию.
Если вы планируете добавить / удалить из середины, используйте LinkedList. Если вы действительно беспокоитесь о размере или часто индексируете прямо в середине коллекции, используйте ArrayList. Оба из них должны иметь операции удаления.
причина: Вы обеспокоены размером или хотите контролировать выделение памяти
решение: используйте ArrayList с определенным начальным размером.
ArrayList-это просто массив, который может расширяться сам по себе, но это не всегда нужно делать. Это будет очень умно о добавлении / удалении элементов, но опять же, если вы вставляете/удаляете много из середины, используйте LinkedList.
причина: у вас есть массив, входящий и выходящий массив-поэтому вы хотите работать с массивом
решение: преобразовать его в ArrayList, удалить элемент и преобразовать его обратно
причина: вы думаете, что можете написать лучший код, если вы это сделаете сам
решение: вы не можете использовать массив или связанный список.
причина: это назначение класса, и вы не можете или у вас нет доступа к API коллекции по какой-то причине
предположение: вам нужно, чтобы новый массив был правильным "размером"
решение: Сканируйте массив на наличие совпадающих элементов и подсчитайте их. Создайте новый массив правильного размера (исходный размер - количество совпадений). использование системы.arraycopy неоднократно копировать каждую группу элементов, которые вы хотите сохранить в новый массив. Если это домашнее задание и вы не можете использовать систему.arraycopy, просто скопируйте их по одному вручную в цикле, но никогда не делайте этого в производственном коде, потому что это намного медленнее. (Эти решения подробно описаны в других ответах)
причина: вам нужно запустить голый металл
предположение: вы не должны выделять пространство без необходимости или принимать слишком долго
предположение: вы отслеживаете размер, используемый в массиве (длина) отдельно, потому что в противном случае вам придется перераспределить массив для удаления/вставки.
пример того, почему вы можете это сделать: один массив примитивов (скажем, значения int) занимает значительный кусок вашего ОЗУ-например, 50%! ArrayList заставит их в список указателей на целочисленные объекты, которые будут использовать в несколько раз больше памяти.
решение: Повторите свой массив и всякий раз, когда вы найдете элемент для удаления (назовем его элементом n), используйте System.arraycopy для копирования хвоста массива над "удаленным" элементом (источник и назначение-один и тот же массив) - достаточно умно сделать копию в правильном направлении, чтобы память не перезаписывала себя:
System.arraycopy(ary, n+1, ary, n, length-n) length--;вы, вероятно, хотите быть умнее, чем это, если вы удаляете более чем один элемент одновременно. Вы бы только переместить область между одним "матч" и далее, а не весь хвост и, как всегда, избегайте перемещения любого куска дважды.
в этом последнем случае, вы абсолютно должны сделать работу самостоятельно, и с помощью системы.arraycopy-это действительно единственный способ сделать это, так как он собирается выбрать лучший способ перемещения памяти для вашей компьютерной архитектуры-он должен быть во много раз быстрее, чем любой код, который вы могли бы написать самостоятельно.
Это зависит от того, что вы подразумеваете под "удалить"? Массив является конструкцией фиксированного размера - вы не можете изменить количество элементов в нем. Таким образом, вы можете либо a) создать новый, более короткий массив без элементов, которые вы не хотите, либо b) назначить записи, которые вы не хотите, чему-то, что указывает на их "пустой" статус; обычно null, если вы не работаете с примитивами.
в первом случае создайте список из массива, удалите элементы и создайте новый массив из списка. Если производительность важна итерация по массиву, назначая любые элементы, которые не должны быть удалены в список, а затем создать новый массив из списка. Во втором случае просто пройдите и назначьте null для записей массива.
Arrgh, я не могу получить код, чтобы показать правильно. Извини, у меня получилось. Извините еще раз, я не думаю, что правильно прочитал вопрос.
String foo[] = {"a","cc","a","dd"}, remove = "a"; boolean gaps[] = new boolean[foo.length]; int newlength = 0; for (int c = 0; c<foo.length; c++) { if (foo[c].equals(remove)) { gaps[c] = true; newlength++; } else gaps[c] = false; System.out.println(foo[c]); } String newString[] = new String[newlength]; System.out.println(""); for (int c1=0, c2=0; c1<foo.length; c1++) { if (!gaps[c1]) { newString[c2] = foo[c1]; System.out.println(newString[c2]); c2++; } }
будут скопированы все элементы, кроме одного с индексом i:
if(i == 0){ System.arraycopy(edges, 1, copyEdge, 0, edges.length -1 ); }else{ System.arraycopy(edges, 0, copyEdge, 0, i ); System.arraycopy(edges, i+1, copyEdge, i, edges.length - (i+1) ); }
class sd { public static void main(String[ ] args) { System.out.println("Search and Delete"); int key; System.out.println("Enter the length of array:"); Scanner in=new Scanner(System.in); int n=in.nextInt(); int numbers[]=new int[n]; int i = 0; boolean found = false; System.out.println("Enter the elements in Array :"); for ( i = 0; i < numbers.length; i++) { numbers[i]=in.nextInt(); } System.out.println("The elements in Array are:"); for ( i = 0; i < numbers.length; i++) { System.out.println(numbers[i]); } System.out.println("Enter the element to be searched:"); key=in.nextInt(); for ( i = 0; i < numbers.length; i++) { if (numbers[ i ] == key) { found = true; break; } } if (found) { System.out.println("Found " + key + " at index " + i + "."); numbers[i]=0;//haven't deleted the element in array System.out.println("After Deletion:"); for ( i = 0; i < numbers.length; i++) { if (numbers[ i ]!=0) { //it skips displaying element in array System.out.println(numbers[i]); } } } else { System.out.println(key + "is not in this array."); } } }//Sorry.. if there are mistakes.