86

给定一个包含n 个对象的数组,假设它是一个字符串数组,它具有以下值:

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

我该怎么做才能删除/删除数组中等于“a”的所有字符串/对象?

4

20 回答 20

114

[如果你想要一些现成的代码,请滚动到我的“Edit3”(剪切后)。其余的留给后代。]

充实Dustman的想法

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

Edit2:上述方法保留相同的数组(因此数组仍然是相同的长度);最后一个元素设置为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每次调用您的函数时都会被编辑。

愤世嫉俗的人的建议(见评论)也将有助于乱扔垃圾,为了公平起见,我应该提一下:

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

我更喜欢我的方法,因为它可能更容易弄错明确的大小(例如,调用size()错误的列表)。

于 2008-09-21T23:30:33.667 回答
32

Java 8 中的替代方案:

String[] filteredArray = Arrays.stream(array)
    .filter(e -> !e.equals(foo)).toArray(String[]::new);
于 2014-04-20T23:44:12.827 回答
20

使用List,从数组中创建一个Arrays.asList(),并调用remove()所有适当的元素。然后调用toArray()“列表”再次返回数组。

性能不是很好,但如果你正确封装它,你以后总是可以更快地做一些事情。

于 2008-09-21T23:18:06.753 回答
15

你总是可以这样做:

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);
于 2008-09-23T06:55:15.150 回答
7

您可以使用外部库:

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

它在项目 Apache Commons Lang http://commons.apache.org/lang/

于 2011-02-04T14:41:12.980 回答
6

请参阅下面的代码

ArrayList<String> a = new ArrayList<>(Arrays.asList(strings));
a.remove(i);
strings = new String[a.size()];
a.toArray(strings);
于 2014-01-26T20:37:36.540 回答
5

如果您需要从数组中删除多个元素而不将其转换为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().

于 2015-05-10T12:12:32.203 回答
4

这里有很多答案 - 我看到的问题是你没有说为什么你使用数组而不是集合,所以让我提出几个原因以及哪些解决方案将适用(大多数解决方案这里的其他问题已经回答了,所以我不会太详细):

原因:您不知道收藏包存在或不信任它

解决方案:使用集合。

如果您打算从中间添加/删除,请使用 LinkedList。如果您真的担心大小或经常索引到集合的中间,请使用 ArrayList。这两个都应该有删除操作。

原因:您关心大小或希望控制内存分配

解决方案:使用具有特定初始大小的 ArrayList。

ArrayList 只是一个可以扩展自身的数组,但它并不总是需要这样做。添加/删除项目将非常聪明,但是如果您要从中间插入/删除很多,请再次使用 LinkedList。

原因:你有一个数组进来和一个数组出去——所以你想对一个数组进行操作

解决方案:将其转换为ArrayList,删除该项目并将其转换回

原因:你认为如果你自己做,你可以写出更好的代码

解决方案:你不能,使用数组或链表。

原因:这是一项课堂作业,您不被允许或由于某种原因您无权访问集合 API

假设:您需要新数组是正确的“大小”

解决方案:扫描数组以查找匹配项并计数。创建一个正确大小的新数组(原始大小 - 匹配数)。重复使用 System.arraycopy 将您希望保留的每组项目复制到新数组中。如果这是一个类分配并且您不能使用 System.arraycopy,只需在循环中手动一次复制一个,但不要在生产代码中这样做,因为它要慢得多。(这些解决方案在其他答案中都有详细说明)

原因:你需要运行裸机

假设:您不得不必要地分配空间或花费太长时间

假设:您正在单独跟踪数组中使用的大小(长度),否则您必须为删除/插入重新分配数组。

您可能想要这样做的一个示例:单个基元数组(假设是 int 值)占用了您的 ram 的很大一部分——比如 50%!ArrayList 会强制将它们放入指向 Integer 对象的指针列表,这些对象将使用该内存量的几倍。

解决方案:遍历您的数组,每当您找到要删除的元素(我们称其为元素 n),使用 System.arraycopy 将数组的尾部复制到“已删除”元素上(源和目标是相同的数组) - 它足够聪明,可以按照正确的方向进行复制,因此内存不会覆盖自身:

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

如果您一次删除多个元素,您可能希望比这更聪明。您只会移动一个“匹配”和下一个“匹配”之间的区域,而不是整个尾部,并且一如既往,避免移动任何块两次。

在最后一种情况下,您绝对必须自己完成工作,并且使用 System.arraycopy 确实是唯一的方法,因为它将为您的计算机体系结构选择最佳的内存移动方式——它应该快很多倍比你自己可以合理编写的任何代码。

于 2017-05-24T17:10:32.937 回答
3

关于制作它的列表然后删除然后回到数组​​的事情让我觉得是错误的。尚未测试,但我认为以下会表现更好。是的,我可能过度预优化。

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];
   }
}
于 2008-09-22T12:50:22.027 回答
3

我意识到这是一个非常古老的帖子,但这里的一些答案帮助了我,所以这是我的 tuppence'ha'penny 的价值!

在我认为需要调整我正在写回的数组的大小之前,我努力让它工作了很长一段时间,除非对ArrayList列表大小所做的更改保持不变。

如果ArrayList您正在修改的最终元素比开始时更多或更少,则该行将List.toArray()导致异常,因此您需要类似List.toArray(new String[] {})orList.toArray(new String[0])的东西来创建具有新(正确)大小的数组。

现在听起来很明显,我知道了。对于一个正在掌握新的和不熟悉的代码结构的 Android/Java 新手来说并不是那么明显,而且从这里的一些早期帖子中也不是很明显,所以只是想让其他人像我一样挠头几个小时来弄清楚这一点!

于 2013-07-05T11:49:34.520 回答
2

初始数组

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

如果要删除索引 2 的 51,请使用以下

 for(int i = 2; i < array.length -1; i++){
    array[i] = array[i + 1];
  }
于 2018-11-19T21:47:26.140 回答
1

编辑:

数组中具有空值的点已被清除。对不起我的评论。

原来的:

嗯……线

array = list.toArray(array);

用null替换已删除元素所在的数组中的所有间隙。这可能很危险,因为元素被删除,但数组的长度保持不变!

如果您想避免这种情况,请使用新数组作为 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]

作为 Chris Yester Young 输出的当前接受的答案:

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

没有留下任何空值。

于 2008-09-22T20:20:13.740 回答
1

我对这个问题的贡献不大。

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

}

于 2013-11-30T13:52:34.807 回答
0

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++;
    }
}
于 2008-09-22T12:59:37.747 回答
0

这取决于您所说的“删除”是什么意思?数组是一个固定大小的结构 - 您不能更改其中的元素数量。因此,您可以 a) 创建一个新的、较短的数组,其中不包含您不想要的元素,或者 b) 将您不想要的条目分配给指示其“空”状态的东西;如果您不使用原语,通常为 null。

在第一种情况下,从数组中创建一个列表,删除元素,然后从列表中创建一个新数组。如果性能很重要,则遍历数组,将不应删除的任何元素分配给列表,然后从列表中创建一个新数组。在第二种情况下,只需通过并将 null 分配给数组条目。

于 2008-09-24T21:15:40.847 回答
0

将复制除索引为 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) );
            }
于 2016-06-11T19:00:40.007 回答
0

如果元素的顺序无关紧要。您可以在元素 foo[x] 和 foo[0] 之间交换,然后调用 foo.drop(1)。

foo.drop(n)从数组中删除 (n) 个第一个元素。

我想这是最简单且资源有效的方法。

PSindexOf可以通过多种方式实现,这是我的版本。

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);
}
于 2019-08-06T19:44:22.287 回答
0

  仅  删除具有 lambda的几个相等条目中的第一个

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

可以删除null条目

于 2021-02-24T08:23:39.983 回答
-1

在一个字符串数组中,如

String name = 'abcdeafbd e' // 可以像 String name = 'aa bb cde 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()

得到这个结果

abcdef

希望这段代码对任何人都有帮助

于 2019-06-18T15:40:08.107 回答
-7

将 null 分配给数组位置。

于 2008-09-21T23:19:47.810 回答