【问题标题】:How to remove null from an array in java如何从java中的数组中删除null
【发布时间】:2011-08-29 12:51:43
【问题描述】:

我编写了一个方法来从程序中需要的数组中删除空值。 但是,该方法似乎不起作用,空值不会消失。这是我目前的代码。

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

提前致谢!

【问题讨论】:

  • 这里可能有同样的问题link!
  • 是否可以不允许空值进入数组?

标签: java arrays


【解决方案1】:

除非性能真的是个问题,否则我会提倡用简单的方法来做:

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

【讨论】:

  • +1 - 最简单的代码是最好的,除非真正需要性能。
  • +1 你真的想给'remove'变量一个ArrayList类型吗?我在想List,以尽量减少对实际类型的依赖。
  • @KLE 如果我要返回 ArrayList,这将是一个好主意,因为我可能想通过多态来更改实现,但对于小方法中的类型,这并不重要。
【解决方案2】:

Streams API 版本的解决方案:

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

(我发布这个可能是为了了解一些关于适用性、相对性能等的想法)

【讨论】:

    【解决方案3】:

    大家好,首先我想为我现在学习的英语道歉,这是我的第一篇文章,所以我想尝试把我的解决方案放在这里

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

    【讨论】:

      【解决方案4】:

      您不能在方法中更改对变量的引用并期望它反映在调用方法中。

      您将不得不返回新数组。

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

      【讨论】:

        【解决方案5】:

        这样会更快:

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

        【讨论】:

          【解决方案6】:

          我可以在您的代码中看到两个错误:

          • 您的方法fillArray 没有涵盖i == j 的情况
          • 您的分配a = a2; 没有您认为它可能产生的效果。参数在 Java 中按值传递,并且您的分配不会更改第一个方法中 a 的值。尝试在fillArray 中将实例返回给a2,然后将此值分配给removeNull 中的a

          【讨论】:

            【解决方案7】:

            有几点:

            1. Don't you wantString[] a2 = new String[a.length-1];` 是

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

            不会让length - 1 太短吗?

            1. 您的代码中需要i == j 的案例。这就是 null 没有得到更新的原因。

            2. 您想用第二个函数解决什么问题?考虑到我认为您的问题是什么,这似乎很复杂。

            【讨论】:

              【解决方案8】:

              试试这个(我没有测试过):

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

              【讨论】:

              • 你为什么要把它复制到最后?
              • 因为可能不是每个字段都需要(这意味着我最后有空值)
              【解决方案9】:

              这样你可以在一个周期内删除空值,但它不会调整数组大小:

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

              这个创建一个新数组,但包括两个循环:

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

              您可以考虑使用System.arraycopy 优化该代码。我希望代码有效。

              【讨论】:

              • 我不认为您可以使用 arrayCopy 进行优化。使用 arrayCopy 的任何好处都将丢失在确定何时可以使用它的开销中。我能想到的唯一优化是测试nullCount 是否为零,如果为零则返回原始数组。
              【解决方案10】:

              删除数组中的值时,大小会发生变化,因此您无法保留相同的数组(您可以在末尾推送空值)。

              接近具有自动调整大小的数组的结构是 ArrayList。一种选择是:

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

              性能可能比直接使用数组稍差,但由于数组具有固定大小,因此您需要两个循环数组:

              • 一个来统计非空值的个数
              • 构建数组后,同样的循环复制值。

              这可能也没有理想的性能,而且要做到这一点确实要复杂得多......


              另一种方法是在末尾移动空值,然后创建一个不包含空值的较短数组。这个想法是:

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

              【讨论】:

                【解决方案11】:

                嗯,以前有更多人说过……但我也想强调一下这个解决方案:

                您可以使用某种类型的集合,例如 ArrayList 或 List 并仅添加非空元素。最后你必须返回由 Collection 形成的新 String[]。

                这里是一个可以检查正确性的例子:

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

                带有代码的 for 不打印任何内容,因为存在任何空元素 :)

                问候!

                【讨论】:

                  【解决方案12】:

                  你有两个选择:

                  1. 创建长度与输入相同的新数组,然后为其分配非空值并将其减去到非空元素的计数中。

                    0xJoKe 答案中的示例。

                  2. 如果您只需要使用 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");
                        }
                    
                    }
                    
                    }
                    

                  那么在源代码中,你唯一需要做的就是:

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

                  第二个选项是 != null 条件的非常奇特的用法,但是当方法需要返回一些数据时它可能会有所帮助。

                  【讨论】:

                    猜你喜欢
                    • 1970-01-01
                    • 1970-01-01
                    • 2022-12-29
                    • 2017-08-29
                    • 2019-06-03
                    • 2010-09-11
                    • 2022-01-14
                    • 2022-01-20
                    • 1970-01-01
                    相关资源
                    最近更新 更多