简体   繁体   English

如何从java中的数组中删除null

[英]How to remove null from an array in java

I've written a method to remove null-values from an array i need in a program. 我编写了一个方法来从程序中需要的数组中删除空值。 The method, however, doesn't seem to work, the null values won't go away. 但是,该方法似乎不起作用,空值不会消失。 This is my code so far. 到目前为止这是我的代码。

public void removeNull(String[] a)
{
       for(int i=0; i<a.length; i++)
    {
        if(a[i] == null)
        {
            fillArray(a, i);
        }
    }
}

public void fillArray(String[] a, int i)
{
    String[] a2 = new String[a.length-1];

    for(int j=0; j<a2.length; j++)
    {
            if(j<i)
            {
                a2[j]=a[j];
            }
        else if(j>i)
        {
            a2[j]=a[j+1];
        }
    }

    a=a2;
}

Thanks in advance! 提前致谢!

I would advocate doing it the simple way unless performance is really a problem: 除非性能确实是一个问题,否则我会主张以简单的方式做到这一点:

public String[] removeNull(String[] a) {
   ArrayList<String> removedNull = new ArrayList<String>();
   for (String str : a)
      if (str != null)
         removedNull.add(str);
   return removedNull.toArray(new String[0]);
}

hi everyone first of all i want to appologize for my english im learning at this moment and this is my first post so i want to try to put my solution about the problem here it is 大家好,首先我想为我的英语即时通讯学习,这是我的第一篇文章所以我想尝试在这里解决问题的解决方案

String[] removeNulls(String[] nullsArray) {
    int countNulls = 0;

    for (int i = 0; i < nullsArray.length; i++) { // count nulls in array
        if (nullsArray[i] == null) {
            countNulls++;
        }
    }
    // creating new array with new length (length of first array - counted nulls)
    String[] nullsRemoved = new String[nullsArray.length - countNulls];

    for (int i = 0, j = 0; i < nullsArray.length; i++) {

        if (nullsArray[i] != null) {
            nullsRemoved[j] = nullsArray[i];
            j++;
        }
    }
    return nullsRemoved;
}

Streams API version of the solution: Streams API版解决方案:

SomeClass[] array = new SomeClass[N];
...
array = Arrays.stream(array).filter(Objects::nonNull).toArray(SomeClass[]::new);

(I post this down to maybe get some thoughts on applicability, relative performance etc) (我发布这个可能会对适用性,相对性能等有所了解)

You can't change the reference to a variable in a method and expect it to be reflected in the calling method. 您无法更改方法中对变量的引用,并期望它反映在调用方法中。

You'll instead have to return the new array. 你将不得不返回新的数组。

public String[] removeNull(String[] a)
{
    for(int i=0; i<a.length; i++)
    {
        if(a[i] == null)
        {
            a = fillArray(a, i);
        }
    }

    return a;
}

public String[] fillArray(String[] a, int i)
{
    String[] a2 = new String[a.length-1];

    for(int j=0; j<a2.length; j++)
    {
            if(j<i)
            {
                a2[j]=a[j];
            }
        else if(j>i)
        {
            a2[j]=a[j+1];
        }
    }

    return a2;
}

This way would be faster: 这种方式会更快:

private static String[] removeNulls(String[] strs) {
    int i = 0;
    int j = strs.length - 1;
    while (i <= j) {
        if (strs[j] == null) {
            --j;
        } else if (strs[i] != null) {
            ++i;
        } else {
            strs[i] = strs[j];
            strs[j] = null;
            ++i; --j;
        }
    }


    return Arrays.copyOfRange(strs, 0, i);
}

I can see two errors in your code: 我可以在你的代码中看到两个错误:

  • Your method fillArray doesn't cover the case i == j 你的方法fillArray不包括i == j的情况
  • Your assignation a = a2; 你的任命a = a2; doesn't have the effect you think it might have. 没有你认为它可能具有的效果。 Arguments are passed by value in Java, and your assignment does NOT change the value of a in your first method. 参数是按值在Java中过去了,你的任务不会改变的价值a在你的第一种方法。 Try returning an instance to a2 in fillArray , and assign this value to a in removeNull . 尝试返回一个实例, a2fillArray ,而这个值赋给aremoveNull

A couple of things: 有几件事:

  1. Don't you want String[] a2 = new String[a.length-1];` to be Don't you want String [] a2 = new String [a.length-1];`是的

String[] a2 = new String[a.length];

Won't making it length - 1 make it too short? 不会length - 1让它太短?

  1. You need a case for i == j in your code. 您需要在代码中使用i == j的大小写。 This is why the nulls aren't getting updated. 这就是空值没有得到更新的原因。

  2. What problem are you trying to solve with the second function? 你试图用第二个函数解决什么问题? It seems complicated given what I thought your problem was. 鉴于我认为你的问题是什么,这似乎很复杂。

Try this (I didn't test it): 试试这个(我没试过):

public String[] removeNull(String[] a) {
    String[] tmp = new String[a.length];
    int counter = 0;
    for (String s : a) {
        if (s != null) {
            tmp[counter++] = s;
        }
    }
    String[] ret = new String[counter];
    System.arraycopy(tmp, 0, ret, 0, counter);
    return ret;
}

When removing values in an array, the size changes so you can't keep the same array (you could push the nulls at the end). 删除数组中的值时,大小会更改,因此您无法保持相同的数组(可以在末尾推送空值)。

The structure close to an array that has a auto-adjustable size is an ArrayList. 靠近具有可自动调整大小的数组的结构是ArrayList。 One option would be : 一种选择是:

String[] inputs;
List<String> items = new ArrayList<String>(inputs.length);
for(String input : inputs) {
   if (input != null) {
      items.add(input);
   }
}
String[] outputs = items.toArray(new String[items.size()]);

Performance might be a bit less than working directly with arrays, but because an array has a fixed size, you would need two loops with arrays : 性能可能比直接使用数组少一些,但由于数组具有固定大小,因此需要两个带数组的循环:

  • one to count the number of non-null values 一个来计算非空值的数量
  • after building the array, the same loop to copy the values. 在构建数组之后,使用相同的循环来复制值。

This might not have an ideal performance either, and it is really much more complex to get it right... 这可能也没有理想的性能,而且要做到这一点真的要复杂得多......


Another approach would be to move the nulls at the end, then create a shorter array that wouldn't include the nulls. 另一种方法是在末尾移动空值,然后创建一个不包含空值的较短数组。 The idea would be : 这个想法是:

String[] strings;
int writeIndex = 0;
int max = strings.length;
for(int readIndex = 0; readIndex < max; readIndex++) {
   String read = strings[readIndex];
   if (read != null) {
      strings[writeIndex++] = read;
   }
}
String[] outputs = new String[writeIndex];
System.arraycopy(strings, 0, ouputs, 0, writeIndex);

This way you can remove nulls in one cycle, but it will not resize array: 这样您就可以在一个循环中删除空值,但不会调整数组的大小:

public static void removeNull(String[] a) {
    int nullCount = 0;
    for (int i = 0; i < a.length; i++) {
        if (a[i] == null) {
            nullCount++;
        } else {
            a[i-nullCount] = a[i];
        }
    }
}

This one creates new array, but includes two cycles: 这个创建新数组,但包括两个周期:

public static String[] removeNull(String[] a) {
    int nullCount = 0;
    for (int i = 0; i < a.length; i++) {
        if (a[i] == null) nullCount++;
    }
    String[] b = new String[a.length-nullCount];
    int j = 0;
    for (int i = 0; i < a.length; i++) {
        if (a[i] != null) b[j++] = a[i];
    }
    return b;
}

You can think on optimizing that code using System.arraycopy . 您可以考虑使用System.arraycopy优化该代码。 I hope the code works. 我希望代码有效。

You have two options: 您有两种选择:

  1. Create new array that length is same as the input, then assign to it not null values and add the substract it to the count of not null elememts . 创建长度与输入相同的新数组,然后为其分配非空值,并将其减去非空元素的计数。

    Example in 0xJoKe answer. 0xJoKe答案中的示例。

  2. If You need to work only sutch array you could create an adapter for it. 如果您只需要工作sutch数组,您可以为它创建一个适配器。

     public class NullProofIterable<T> implements Iterable<T>{ private final T[] array; public NullProofIterable(T[] array){ this.array = array; } @Override public Iterator<T> iterator() { return new NullProofIterator<T>(this.array); } private static class NullProofIterator<T> implements Iterator<T> { private final T[] array; private final int index = 0; private NullProofIterator(T[] array) { this.array = array; } @Override public boolean hasNext() { return this.index < this.array.length; } @Override public T next() { return this.array[this.index]; } @Override public void remove() { throw new RuntimeException("Remove not allowed in this iterator"); } } } 

Then in source code, only thing you have to do is: 然后在源代码中,您唯一需要做的就是:

for(String str : new NullProofIterable<String>(strArray)) {
    //Perform action on not null string         
}

The second option is very fancy usage of != null condition bu it might be helful when a method need to return some data. 第二个选项是非常奇特的使用!= null条件,当方法需要返回一些数据时,它可能很有用。

Well, more people said it before... but I also want to emphasize this solution: 好吧,之前有更多人说过......但我也想强调这个解决方案:

You can use some type of Collection, like ArrayList or List and add only the not null elements. 您可以使用某种类型的Collection,如ArrayList或List,并仅添加非null元素。 Finally you must return the new String[] formed by the Collection. 最后,您必须返回Collection形成的新String []。

Here an example where you can check the correctness: 这是一个可以检查正确性的示例:

import java.util.ArrayList;

public class NullRemove {

    public static String[] removeNull(String[] a) {
        ArrayList<String> aux = new ArrayList<String>();
        for (String elem : a) {
            if (elem != null) {
                aux.add(elem);
            }
        }
        return (String[]) aux.toArray(new String[aux.size()]);
    }
    public static void main(String[] args) {
        String[] init = new String[]{"aaa", null, "bbb", "ccc", null, "ddd", 
            "eee", "fff", null};

        String[] result = NullRemove.removeNull(init);

        System.out.println("Start Check result");

        for (String elem : result) {
            if (elem == null) System.out.println("NULL element");
        }

        System.out.println("End Check result");
    }
}

The for with the code don't print anything cause there is any null element :) 带代码的for不打印任何因为有任何null元素:)

Regards! 问候!

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

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