Как удалить объекты из массива в Java?


дан массив n объекты, скажем, это массив строк, и имеет следующие значения:

foo[0] = "a";
foo[1] = "cc";
foo[2] = "a";
foo[3] = "dd";

что мне нужно сделать, чтобы удалить / удалить все строки / объекты, равные "а" в массиве?

18 69

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 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.

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

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

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