Как мне удалить объекты из массива в Java?
-
02-07-2019 - |
Вопрос
Задан массив из n Объекты, допустим, это массив строк, и он имеет следующие значения:
foo[0] = "a";
foo[1] = "cc";
foo[2] = "a";
foo[3] = "dd";
Что мне нужно сделать, чтобы удалить все строки / объекты, равные "а" в массиве?
Решение
[Если вам нужен готовый к использованию код, пожалуйста, перейдите к моему "Edit3" (после вырезки).Остальное здесь для потомков.]
Чтобы конкретизировать Идея Мусорщика:
List<String> list = new ArrayList<String>(Arrays.asList(array));
list.removeAll(Arrays.asList("a"));
array = list.toArray(array);
Редактировать:Теперь я использую Arrays.asList
вместо того, чтобы Collections.singleton
:синглтон ограничен одной записью, в то время как asList
подход позволяет вам добавлять другие строки для последующей фильтрации: Arrays.asList("a", "b", "c")
.
Редактировать 2:Приведенный выше подход сохраняет тот же массив (таким образом, массив остается той же длины).;элементу после последнего присваивается значение null.Если вы хотите новое размер массива точно соответствует требуемому, используйте это вместо:
array = list.toArray(new String[0]);
Редактировать 3:Если вы часто используете этот код в одном и том же классе, возможно, вы захотите добавить его в свой класс:
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
редактируйте каждый раз, когда вызывается ваша функция.
предложение cynicalman (см. Комментарии) также поможет с засорением кучи, и справедливости ради я должен упомянуть об этом:
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, который только начинает разбираться с новыми и незнакомыми конструкциями кода, и не очевидно из некоторых предыдущих постов здесь, поэтому просто хотел прояснить этот момент для всех, кто еще часами ломает голову, как я!
Здесь много ответов - проблема, как я вижу, в том, что вы не сказали, ПОЧЕМУ вы используете массив вместо коллекции, поэтому позвольте мне предложить пару причин и какие решения будут применимы (на большинство решений уже были даны ответы в других вопросах здесь, поэтому я не буду вдаваться в подробности):
Причина:Вы не знали о существовании пакета сбора данных или не доверяли ему
решение:Используйте коллекцию.
Если вы планируете добавлять / удалять из середины, используйте LinkedList.Если вы действительно беспокоитесь о размере или часто индексируете прямо в середине коллекции, используйте ArrayList.Оба они должны содержать операции удаления.
Причина:Вас беспокоит размер или вы хотите контролировать распределение памяти
решение:Используйте ArrayList с определенным начальным размером.
ArrayList - это просто массив, который может расширяться сам по себе, но ему не всегда нужно это делать.Это будет очень разумно при добавлении / удалении элементов, но опять же, если вы вставляете / удаляете МНОГО из середины, используйте LinkedList.
Причина:У вас есть входящий массив и выходящий массив - итак, вы хотите оперировать с массивом
решение:Преобразуйте его в ArrayList, удалите элемент и преобразуйте его обратно
Причина:Вы думаете, что сможете написать лучший код, если сделаете это сами
решение:вы не можете использовать Массив или Связанный список.
Причина:это назначение класса, и по какой-то причине вам не разрешено или у вас нет доступа к API-интерфейсам collection
предположение:Вам нужно, чтобы новый массив был правильного "размера".
решение:Просканируйте массив на наличие совпадающих элементов и подсчитайте их.Создайте новый массив правильного размера (исходный размер - количество совпадений).используйте System.arraycopy повторно, чтобы скопировать каждую группу элементов, которые вы хотите сохранить, в ваш новый массив.Если это назначение класса, и вы не можете использовать System.arraycopy, просто скопируйте их по одному вручную в цикле, но никогда не делайте этого в производственном коде, потому что это намного медленнее.(Оба этих решения подробно описаны в других ответах)
Причина:вам нужно использовать голый металл
предположение:вы НЕ ДОЛЖНЫ выделять пространство без необходимости или занимать слишком много времени
предположение:Вы отслеживаете размер, используемый в массиве (длину), отдельно, потому что в противном случае вам пришлось бы перераспределять ваш массив для удаления / вставки.
Пример того, почему вы, возможно, захотите это сделать:один массив примитивов (скажем, значений int) занимает значительную часть вашей оперативной памяти - примерно 50%!ArrayList принудительно преобразовал бы их в список указателей на целочисленные объекты, которые использовали бы в несколько раз больший объем памяти.
решение:Выполните итерацию по вашему массиву и всякий раз, когда вы находите элемент для удаления (назовем его элементом n), используйте System.arraycopy, чтобы скопировать конец массива поверх "удаленного" элемента (источник и назначение - это один и тот же массив) - он достаточно умен, чтобы выполнить копирование в правильном направлении, чтобы память не перезаписывала себя:
System.arraycopy(ary, n+1, ary, n, length-n) length--;
Вероятно, вам захочется быть умнее, если вы удаляете более одного элемента одновременно.Вы бы перемещали только область между одной "спичкой" и следующей, а не весь хвост и, как всегда, избегали бы перемещения любого фрагмента дважды.
В этом последнем случае вам абсолютно необходимо выполнить всю работу самостоятельно, и использование System.arraycopy - действительно единственный способ сделать это, поскольку он собирается выбрать наилучший возможный способ перемещения памяти для вашей компьютерной архитектуры - это должно быть во много раз быстрее, чем любой код, который вы могли бы разумно написать самостоятельно.
Редактировать:
Точка с нулевыми значениями в массиве была очищена.Извините за мои комментарии.
Оригинал:
Ehm...линия
array = list.toArray(array);
заменяет все пробелы в массиве, где был удаленный элемент с ноль.Это может быть опасный, потому что элементы удаляются, но длина массива остается прежней!
Если вы хотите избежать этого, используйте новый массив в качестве параметра для toArray().Если вы не хотите использовать removeAll, альтернативой может быть Set:
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));
без каких-либо нулевых значений, оставшихся после.
Мой небольшой вклад в решение этой проблемы.
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;
}
}
Начальный массив
int[] array = {5,6,51,4,3,2};
если вы хотите удалить 51, который является индексом 2, используйте следующее
for(int i = 2; i < array.length -1; i++){
array[i] = array[i + 1];
}
Это зависит от того, что вы подразумеваете под "удалить"?Массив - это конструкция фиксированного размера - вы не можете изменить количество элементов в нем.Таким образом, вы можете либо а) создать новый, более короткий массив без элементов, которые вам не нужны, либо б) присвоить ненужным записям что-то, что указывает на их статус "пусто";обычно null, если вы не работаете с примитивами.
В первом случае создайте список из массива, удалите элементы и создайте новый массив из списка.Если важна производительность, выполните итерацию по массиву, назначив все элементы, которые не следует удалять, в список, а затем создайте новый массив из списка.Во втором случае просто пройдите и присвоите null элементам массива.
Арррх, я не могу заставить код отображаться корректно.Извини, у меня все получилось.Еще раз извините, мне кажется, я неправильно прочитал вопрос.
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) );
}
В массиве строк типа
String name = 'a b c d e a f b d e' // может быть как String name = 'aa bb c d e aa f bb d e'
Я создаю следующий класс
class clearname{
def parts
def tv
public def str = ''
String name
clearname(String name){
this.name = name
this.parts = this.name.split(" ")
this.tv = this.parts.size()
}
public String cleared(){
int i
int k
int j=0
for(i=0;i<tv;i++){
for(k=0;k<tv;k++){
if(this.parts[k] == this.parts[i] && k!=i){
this.parts[k] = '';
j++
}
}
}
def str = ''
for(i=0;i<tv;i++){
if(this.parts[i]!='')
this.str += this.parts[i].trim()+' '
}
return this.str
}}
return new clearname(name).cleared()
получение этого результата
a b c d e f
надеюсь, этот код кому-нибудь поможет С уважением
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.
Использование:
list.removeAll(...);
//post what char you need in the ... section
Присвоите null расположениям массива.