【问题标题】:Remove trailing zeroes from ArrayList in Java从 Java 中的 ArrayList 中删除尾随零
【发布时间】:2020-01-25 02:00:45
【问题描述】:

对于给定的输入 ArrayList,我希望保留非零元素之间的所有前导或 0,但希望摆脱 ArrayList 中任意数量的尾随 0。

输入:

0, 11, 0, 0, 0, 11, 11, 0, 0, 0

预期输出:

0、11、0、0、0、11、11

我的解决方案:

    private List<Integer> foo() {

        List<Integer> list = Arrays.asList(0, 11, 0, 0, 0, 11, 11, 0, 0, 0);
        Collections.reverse(list);
        Iterator<Integer> iterator = list.iterator();
        int i = 0;
        while (iterator.hasNext() && 0 != iterator.next()) {
            ++i;
        }
        return list.subList(0, i);
    }

我做错了什么?有没有更好的方法来做到这一点?

【问题讨论】:

  • 您的程序是否给出了错误的输出?如果是这样,请将其包含在问题中。

标签: java arraylist iterator java-stream


【解决方案1】:
  • 该问题与示例代码相矛盾,因为它特别提到了一个 ArrayList(您的示例代码中没有 ArrayList)并说“摆脱”,这意味着删除项目:
    • 您的输入列表具有固定大小(通过Arrays#asList)。
    • 您使用的是List#subList,它不会修改输入列表。
  • 因为您专门询问了 ArrayList,所以一个合理的目标是避免多次代价高昂的调整大小操作。所以对于这样的问题,在你知道如何/是否改变它之后,试着找到最有效的方法来改变最后的列表。
  • 您正在反转输入但没有反转结果,这意味着结果大部分是向后的。您需要再次致电Collections#reverse
  • 倒车很浪费。
    • 一般来说,避免仅仅为了修改集合的一部分(结尾)或回答有关集合的问题(尾随零从哪里开始?)而对整个集合进行更改。
    • 由于 ArrayList 具有快速的随机访问,您可以像从头开始一样轻松快速地从末尾向后迭代,因此反向操作没有任何好处。

因为你的问题是自相矛盾的,这里有两种方法:

  • 不改变原始列表:

    private List<Integer> foo(ArrayList<Integer> list) {
        int size = list.size();
        int lastNonZero = size - 1;
    
        // Iterate from the end until we hit a non-zero
        while (lastNonZero >= 0 && list.get(lastNonZero) == 0) {
            lastNonZero--;
        }
    
        // Truncate if there were trailing zeroes (and at least one non-zero)
        if (lastNonZero < size - 1 && lastNonZero >= 0) {
            list = list.subList(0, lastNonZero);
        }
    
        // Optional copy for safety:  list = new ArrayList<>(list);
    
        return list;
     }
    
  • 有突变:

    private void foo(ArrayList<Integer> list) {           
        int size = list.size();
        int lastNonZero = size - 1;
    
        // Iterate from the end until we hit a non-zero
        while (lastNonZero >= 0 && list.get(lastNonZero) == 0) {
            lastNonZero--;
        }
    
        // Truncate if there were trailing zeroes (and at least one non-zero)
        if (lastNonZero < size - 1 && lastNonZero >= 0) {
            list.subList(lastNonZero + 1, size).clear();
        }
     }
    

注意:改变列表的最快方法可能是改用ArrayList#removeRange,但因为它是protected,你需要继承ArrayList 来调用它。

【讨论】:

    【解决方案2】:

    @azurefrog 的解决方案是最简单的。

    我们还可以利用 ListIterator 类一直到最后并在删除零的同时迭代我们的方式(这几乎是迄今为止我发现使用 previous()hasPrevious() 的唯一好处) :

    private List<Integer> foo() {
    
        ArrayList<Integer> list = new ArrayList<Integer>(Arrays.asList(0, 11, 0, 0, 0, 11, 11, 0, 0, 0));
        ListIterator<Integer> iterator = list.listIterator();
        // go to end
        while (iterator.hasNext()) {
          iterator.next();
        }        
        // remove zeros
        while (iterator.hasPrevious() && 0 == iterator.previous(list.size())) {
            iterator.remove();
        }
        System.out.println(Arrays.toString(list.toArray())); // [0, 11, 0, 0, 0, 11, 11]
        return list;
    }
    

    repl

    【讨论】:

    • 不要像while (iterator.hasNext()) { iterator.next(); }那样循环到结尾,而是首先使用list.listIterator(list.size())……这可以与for循环一起使用,即for(ListIterator&lt;Integer&gt; i = list.listIterator(list.size()); i.hasPrevious() &amp;&amp; 0 == i.previous(); ) i.remove();,这几乎就像另一个答案。而且不需要Arrays.toString(list.toArray());因为您可以简单地通过System.out.println(list); 打印,这将产生完全相同的输出。
    【解决方案3】:

    你的代码需要改变三件事

    在你迭代的条件下,把它变成这样,你想继续计数零

    while (iterator.hasNext() && 0 == iterator.next()) {
    

    在计算完尾随零后反转

    Collections.reverse(list);
    

    sublist0list.size() - i;

    完整代码

    List<Integer> list = Arrays.asList(0, 11, 0, 0, 0, 11, 11, 0, 0, 0);
    Collections.reverse(list);
    Iterator<Integer> iterator = list.iterator();
    int i = 0;
    while (iterator.hasNext() && 0 == iterator.next()) {
      ++i;
    }
    Collections.reverse(list);
    return list.subList(0, list.size() - i);
    

    【讨论】:

      【解决方案4】:

      当然,如果它是 0,只需删除最后一个元素。重复直到没有。

      例如

          List<Integer> list = new ArrayList<>(Arrays.asList(0, 11, 0, 0, 0, 11, 11, 0, 0, 0));
          while (list.get(list.size()-1) == 0) {
              list.remove(list.size()-1);
          }
          System.out.println(list); // [0, 11, 0, 0, 0, 11, 11]
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2013-07-20
        • 2012-07-01
        • 2012-07-02
        • 2015-06-16
        • 2011-05-30
        • 2012-06-28
        • 1970-01-01
        • 2020-08-09
        相关资源
        最近更新 更多