Как удалить объекты из массива в 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);

это прекратит засорять вашу кучу бесполезными пустыми строковыми массивами, которые в противном случае были бы newed каждый время вызова вашей функции.

предложение циника (см. комментарии) также поможет с мусором кучи, и для справедливости я должен упомянуть об этом:

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 langhttp://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, удалить элемент и преобразовать его обратно

причина: вы думаете, что можете написать лучший код, если вы это сделаете себя!--5-->

решение: вы не можете использовать массив или связанный список.

причина: это назначение класса, и вы не разрешены или у вас нет доступа к API коллекции по какой-либо причине

предположение: вам нужен новый массив, чтобы быть правильным "размером"

решение: Просканируйте массив на предмет совпадения элементов и подсчитайте их. Создайте новый массив правильного размера (исходный размер - количество совпадений). использование системы.arraycopy неоднократно копировать каждую группу элементов, которые вы хотите сохранить в новый массив. Если это назначение класса, и вы не можете использовать System.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.

использование:

list.removeAll(...);
//post what char you need in the ... section

присвоить null местоположениям массива.