简体   繁体   English

如何从 Java 中的数组中删除对象?

[英]How do I remove objects from an array in Java?

Given an array of n Objects, let's say it is an array of strings , and it has the following values:给定一个包含n 个对象的数组,假设它是一个字符串数组,它具有以下值:

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

What do I have to do to delete/remove all the strings/objects equal to "a" in the array?我该怎么做才能删除/删除数组中等于“a”的所有字符串/对象?

[If you want some ready-to-use code, please scroll to my "Edit3" (after the cut). [如果你想要一些现成的代码,请滚动到我的“Edit3”(剪切后)。 The rest is here for posterity.]其余的留在这里供后代使用。]

To flesh out Dustman's idea :充实 Dustman 的想法

List<String> list = new ArrayList<String>(Arrays.asList(array));
list.removeAll(Arrays.asList("a"));
array = list.toArray(array);

Edit: I'm now using Arrays.asList instead of Collections.singleton : singleton is limited to one entry, whereas the asList approach allows you to add other strings to filter out later: Arrays.asList("a", "b", "c") .编辑:我现在使用Arrays.asList而不是Collections.singleton :单例仅限于一个条目,而asList方法允许您添加其他字符串以稍后过滤: Arrays.asList("a", "b", "c")

Edit2: The above approach retains the same array (so the array is still the same length); Edit2:上面的方法保留了相同的数组(所以数组仍然是相同的长度); the element after the last is set to null.最后一个之后的元素设置为空。 If you want a new array sized exactly as required, use this instead:如果您想要一个大小完全符合要求的数组,请改用:

array = list.toArray(new String[0]);

Edit3: If you use this code on a frequent basis in the same class, you may wish to consider adding this to your class: Edit3:如果您在同一个类中经常使用此代码,您可能希望考虑将其添加到您的类中:

private static final String[] EMPTY_STRING_ARRAY = new String[0];

Then the function becomes:那么函数就变成了:

List<String> list = new ArrayList<>();
Collections.addAll(list, array);
list.removeAll(Arrays.asList("a"));
array = list.toArray(EMPTY_STRING_ARRAY);

This will then stop littering your heap with useless empty string arrays that would otherwise be new ed each time your function is called.然后,这将停止用无用的空字符串数组乱扔堆,否则每次调用函数时都会new ed。

cynicalman's suggestion (see comments) will also help with the heap littering, and for fairness I should mention it:愤世嫉俗的人的建议(见评论)也将有助于堆垃圾,为了公平起见,我应该提到它:

array = list.toArray(new String[list.size()]);

I prefer my approach, because it may be easier to get the explicit size wrong (eg, calling size() on the wrong list).我更喜欢我的方法,因为它可能更容易得到错误的显式大小(例如,在错误的列表上调用size() )。

An alternative in Java 8: Java 8 中的替代方案:

String[] filteredArray = Arrays.stream(array)
    .filter(e -> !e.equals(foo)).toArray(String[]::new);

Make a List out of the array with Arrays.asList() , and call remove() on all the appropriate elements.使用Arrays.asList()从数组中Arrays.asList()一个List ,并在所有适当的元素上调用remove() Then call toArray() on the 'List' to make back into an array again.然后在“列表”上调用toArray()以再次返回数组。

Not terribly performant, but if you encapsulate it properly, you can always do something quicker later on.性能不是很好,但是如果您正确地封装它,您以后总是可以更快地做一些事情。

You can always do:你总是可以这样做:

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);

You can use external library:您可以使用外部库:

org.apache.commons.lang.ArrayUtils.remove(java.lang.Object[] array, int index)

It is in project Apache Commons Lang http://commons.apache.org/lang/它在 Apache Commons Lang 项目中http://commons.apache.org/lang/

See code below见下面的代码

ArrayList<String> a = new ArrayList<>(Arrays.asList(strings));
a.remove(i);
strings = new String[a.size()];
a.toArray(strings);

If you need to remove multiple elements from array without converting it to List nor creating additional array, you may do it in O(n) not dependent on count of items to remove.如果您需要从数组中删除多个元素而不将其转换为List或创建额外的数组,您可以在 O(n) 中执行此操作,而不依赖于要删除的项目数。

Here, a is initial array, int... r are distinct ordered indices (positions) of elements to remove:这里, 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"
}  

Small testing:小测试:

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]

In your task, you can first scan array to collect positions of "a", then call removeItems() .在您的任务中,您可以先扫描数组以收集“a”的位置,然后调用removeItems()

There are a lot of answers here--the problem as I see it is that you didn't say WHY you are using an array instead of a collection, so let me suggest a couple reasons and which solutions would apply (Most of the solutions have already been answered in other questions here, so I won't go into too much detail):这里有很多答案——我看到的问题是你没有说你为什么使用数组而不是集合,所以让我提出几个原因以及哪些解决方案适用(大多数解决方案已经在其他问题中得到了回答,所以我不再赘述):

reason: You didn't know the collection package existed or didn't trust it原因:您不知道收集包存在或不信任它

solution: Use a collection.解决方案:使用集合。

If you plan on adding/deleting from the middle, use a LinkedList.如果您打算从中间添加/删除,请使用 LinkedList。 If you are really worried about size or often index right into the middle of the collection use an ArrayList.如果您真的很担心大小或经常索引到集合的中间,请使用 ArrayList。 Both of these should have delete operations.这两个都应该有删除操作。

reason: You are concerned about size or want control over memory allocation原因:您担心大小或想要控制内存分配

solution: Use an ArrayList with a specific initial size.解决方案:使用具有特定初始大小的 ArrayList。

An ArrayList is simply an array that can expand itself, but it doesn't always need to do so. ArrayList 只是一个可以扩展自身的数组,但并不总是需要这样做。 It will be very smart about adding/removing items, but again if you are inserting/removing a LOT from the middle, use a LinkedList.添加/删除项目将非常聪明,但是如果您要从中间插入/删除很多,请使用 LinkedList。

reason: You have an array coming in and an array going out--so you want to operate on an array原因:你有一个数组进来,一个数组出去——所以你想对一个数组进行操作

solution: Convert it to an ArrayList, delete the item and convert it back解决方案:将其转换为ArrayList,删除该项目并将其转换回来

reason: You think you can write better code if you do it yourself理由:你认为如果你自己做,你可以写出更好的代码

solution: you can't, use an Array or Linked list.解决方案:你不能,使用数组或链表。

reason: this is a class assignment and you are not allowed or you do not have access to the collection apis for some reason原因:这是一个课堂作业,您不被允许或由于某种原因无法访问集合 api

assumption: You need the new array to be the correct "size"假设:您需要新数组是正确的“大小”

solution: Scan the array for matching items and count them.解决方案:扫描数组中的匹配项并对其进行计数。 Create a new array of the correct size (original size - number of matches).创建一个正确大小的新数组(原始大小 - 匹配数)。 use System.arraycopy repeatedly to copy each group of items you wish to retain into your new Array.重复使用 System.arraycopy 将您希望保留的每组项目复制到新数组中。 If this is a class assignment and you can't use System.arraycopy, just copy them one at a time by hand in a loop but don't ever do this in production code because it's much slower.如果这是一个类分配并且您不能使用 System.arraycopy,只需在循环中手动一次复制它们,但永远不要在生产代码中这样做,因为它会慢得多。 (These solutions are both detailed in other answers) (这些解决方案在其他答案中都有详细说明)

reason: you need to run bare metal原因:你需要运行裸机

assumption: you MUST not allocate space unnecessarily or take too long假设:您不得不必要地分配空间或花费太长时间

assumption: You are tracking the size used in the array (length) separately because otherwise you'd have to reallocate your array for deletes/inserts.假设:您正在单独跟踪数组中使用的大小(长度),否则您必须重新分配数组以进行删除/插入。

An example of why you might want to do this: a single array of primitives (Let's say int values) is taking a significant chunk of your ram--like 50%!您可能想要这样做的原因的一个示例:单个原语数组(假设为 int 值)占用了您 ram 的很大一部分——比如 50%! An ArrayList would force these into a list of pointers to Integer objects which would use a few times that amount of memory. ArrayList 会强制将它们放入指向 Integer 对象的指针列表中,这些对象将使用该数量的内存的几倍。

solution: Iterate over your array and whenever you find an element to remove (let's call it element n), use System.arraycopy to copy the tail of the array over the "deleted" element (Source and Destination are same array)--it is smart enough to do the copy in the correct direction so the memory doesn't overwrite itself:解决方案:迭代您的数组,每当您找到要删除的元素(我们称之为元素 n)时,使用 System.arraycopy 将数组的尾部复制到“已删除”元素上(源和目标是相同的数组)--它足够聪明以正确的方向进行复制,因此内存不会覆盖自身:

System.arraycopy(ary, n+1, ary, n, length-n) 
 length--;

You'll probably want to be smarter than this if you are deleting more than one element at a time.如果您一次删除多个元素,您可能希望比这更聪明。 You would only move the area between one "match" and the next rather than the entire tail and as always, avoid moving any chunk twice.您只会在一个“匹配”和下一个“匹配”之间移动区域而不是整个尾部,并且一如既往地避免将任何块移动两次。

In this last case, you absolutely must do the work yourself, and using System.arraycopy is really the only way to do it since it's going to choose the best possibly way to move memory for your computer architecture--it should be many times faster than any code you could reasonably write yourself.在最后一种情况下,您绝对必须自己完成这项工作,并且使用 System.arraycopy 确实是唯一的方法,因为它将为您的计算机体系结构选择最佳的内存移动方式——它应该快很多倍比您自己可以合理编写的任何代码。

Something about the make a list of it then remove then back to an array strikes me as wrong.关于制作它的列表然后删除然后返回到数组的一些事情让我觉得是错误的。 Haven't tested, but I think the following will perform better.还没有测试,但我认为以下会表现得更好。 Yes I'm probably unduly pre-optimizing.是的,我可能进行了过度的预优化。

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];
   }
}

I realise this is a very old post, but some of the answers here helped me out, so here's my tuppence' ha'penny's worth!我意识到这是一个很老的帖子,但这里的一些答案帮助了我,所以这是我的 tuppence' ha'penny 的价值!

I struggled getting this to work for quite a while before before twigging that the array that I'm writing back into needed to be resized, unless the changes made to the ArrayList leave the list size unchanged.除非对ArrayList所做的更改使列表大小保持不变,否则我努力让它工作了很长一段时间,然后才知道我正在写回的数组需要调整大小。

If the ArrayList that you're modifying ends up with greater or fewer elements than it started with, the line List.toArray() will cause an exception, so you need something like List.toArray(new String[] {}) or List.toArray(new String[0]) in order to create an array with the new (correct) size.如果您正在修改的ArrayList的元素比开始时多List.toArray() ,则List.toArray()行将导致异常,因此您需要List.toArray(new String[] {})List.toArray(new String[0])以创建具有新(正确)大小的数组。

Sounds obvious now that I know it.现在我知道了,这听起来很明显。 Not so obvious to an Android/Java newbie who's getting to grips with new and unfamiliar code constructs and not obvious from some of the earlier posts here, so just wanted to make this point really clear for anybody else scratching their heads for hours like I was!对于开始处理新的和不熟悉的代码结构的 Android/Java 新手来说并不那么明显,而且从这里的一些早期帖子中并不明显,所以只想让其他人真正清楚这一点,因为其他人像我一样挠了几个小时!

Initial array初始数组

   int[] array = {5,6,51,4,3,2};

if you want remove 51 that is index 2, use following如果要删除索引 2 的 51,请使用以下内容

 for(int i = 2; i < array.length -1; i++){
    array[i] = array[i + 1];
  }

EDIT:编辑:

The point with the nulls in the array has been cleared.数组中具有空值的点已被清除。 Sorry for my comments.抱歉我的评论。

Original:原来的:

Ehm... the line嗯……那条线

array = list.toArray(array);

replaces all gaps in the array where the removed element has been with null .将数组中已删除元素所在的所有空白替换为null This might be dangerous , because the elements are removed, but the length of the array remains the same!这可能很危险,因为元素被删除了,但数组的长度保持不变!

If you want to avoid this, use a new Array as parameter for toArray().如果您想避免这种情况,请使用新数组作为 toArray() 的参数。 If you don`t want to use removeAll, a Set would be an alternative:如果您不想使用 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));

Gives:给出:

[a, bc, dc, a, ef]
[dc, ef, bc]

Where as the current accepted answer from Chris Yester Young outputs:正如 Chris Yester Young 输出的当前接受的答案:

[a, bc, dc, a, ef]
[bc, dc, ef, null, ef]

with the code用代码

    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));

without any null values left behind.没有留下任何空值。

My little contribution to this problem.我对这个问题的一点贡献。

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;
}

} }

Arrgh, I can't get the code to show up correctly.啊,我无法让代码正确显示。 Sorry, I got it working.对不起,我让它工作了。 Sorry again, I don't think I read the question properly.再次抱歉,我认为我没有正确阅读问题。

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++;
    }
}

It depends on what you mean by "remove"?这取决于您所说的“删除”是什么意思? An array is a fixed size construct - you can't change the number of elements in it.数组是一个固定大小的结构——你不能改变其中的元素数量。 So you can either a) create a new, shorter, array without the elements you don't want or b) assign the entries you don't want to something that indicates their 'empty' status;因此,您可以 a) 创建一个新的、更短的数组,而没有您不想要的元素,或者 b) 将您不想要的条目分配给指示其“空”状态的内容; usually null if you are not working with primitives.如果您不使用原语,通常为 null。

In the first case create a List from the array, remove the elements, and create a new array from the list.在第一种情况下,从数组中创建一个列表,删除元素,然后从列表中创建一个新数组。 If performance is important iterate over the array assigning any elements that shouldn't be removed to a list, and then create a new array from the list.如果性能很重要,则遍历数组,将不应删除的任何元素分配给列表,然后从列表中创建一个新数组。 In the second case simply go through and assign null to the array entries.在第二种情况下,只需通过并将 null 分配给数组条目。

Will copy all elements except the one with index i:将复制除索引为 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) );
            }

If it doesn't matter the order of the elements.如果元素的顺序无关紧要。 you can swap between the elements foo[x] and foo[0], then call foo.drop(1).您可以在元素 foo[x] 和 foo[0] 之间交换,然后调用 foo.drop(1)。

foo.drop(n) removes (n) first elements from the array. foo.drop(n)从数组中删除 (n) 个第一个元素。

I guess this is the simplest and resource efficient way to do.我想这是最简单且资源高效的方法。

PS : indexOf can be implemented in many ways, this is my version. PS : indexOf可以通过多种方式实现,这是我的版本。

Integer indexOf(String[] arr, String value){
    for(Integer i = 0 ; i < arr.length; i++ )
        if(arr[i] == value)
            return i;         // return the index of the element
    return -1                 // otherwise -1
}

while (true) {
   Integer i;
   i = indexOf(foo,"a")
   if (i == -1) break;
   foo[i] = foo[0];           // preserve foo[0]
   foo.drop(1);
}

to remove only the first of several equal entries删除几个相等条目中的第一个
with a lambda使用 lambda

boolean[] done = {false};
String[] arr = Arrays.stream( foo ).filter( e ->
  ! (! done[0] && Objects.equals( e, item ) && (done[0] = true) ))
    .toArray(String[]::new);

can remove null entries可以删除null条目

In an array of Strings like在像这样的字符串数组中

String name = 'abcdeafbde' // could be like String name = 'aa bb cde aa f bb d e' String name = 'abcdeafbde' // 可能类似于 String name = 'aa bb cde aa f bb d e'

I build the following class我建立了以下课程

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()

getting this result得到这个结果

abcdef abcdef

hope this code help anyone Regards希望此代码可以帮助任何人

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.

Use: 采用:

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

将 null 分配给数组位置。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM