【问题标题】:How to remove everything from an ArrayList in Java but the first element如何从Java中的ArrayList中删除所有内容,但第一个元素
【发布时间】:2010-06-23 06:58:54
【问题描述】:

我是java编程新手,一直在用php编程,所以我习惯了这种类型的循环:

int size = mapOverlays.size();
for(int n=1;n<size;n++)
{
    mapOverlays.remove(n);
}

所以我想删除除第一项之外的所有内容,为什么这不起作用?据我所知,删除后,数组键是否重新排列?

【问题讨论】:

  • 据我所知,您正在选择一个名为 itemizedOverlay 的列表的大小,并且您在另一个名为 mapOverlays 的列表上工作。我希望这是正常的;-)
  • 对不起,一个错字,数组是一样的,我编辑了

标签: java arraylist


【解决方案1】:

你可以使用

mapOverlays.subList(1, mapOverlays.size()).clear();

【讨论】:

  • +1 这不是评分最高的答案,这让我难以置信。它既是最简单的编码 ,也可能是最有效的(因为每个 List 实现都将在给定其结构的情况下以最优化的方式执行任务)。
  • 天哪,它在一个小时内从 2 票变成了最高评分!
  • 这是一种有用的写法。但是,如果您实际查看代码,它使用受保护的removeRange,并且与 Plamena 的解决方案基本相同。主要区别在于方法调用的数量以及循环的位置。有了良好的 JIT,我怀疑它们的性能相当相似。显然,大 O 是一样的。
  • @Matthew:这取决于 List 的实现。对于 ArrayList(至少在 OpenJDK 源代码中),removeRange 调用 System.arraycopy 一次并且不进行其他方法调用。在这种特殊情况下,它移动了 0 个元素,所以基本上它所做的只是在紧密循环中将数组元素设置为 null 并更新 size 字段。
【解决方案2】:

据我所知,删除后,数组键是否重新排列? 是的,在您移除位置 1 上的项目后,位置 2 上的项目位于位置 1。

你可以试试这个:

Object obj = mapOverlays.get(0); // remember first item
mapOverlays.clear(); // clear complete list
mapOverlays.add(obj); // add first item

【讨论】:

  • 这可能有效,但会导致列表进入不必要的中间状态。如果列表同时使用(可能是 CopyOnWriteArrayList),则应避免使用此解决方案。
【解决方案3】:

你为什么不向后尝试?

int size = itemizedOverlay.size();
for(int n=size-1;n>0;n--)
{
    mapOverlays.remove(n);
}

【讨论】:

  • -1 在某些 List 实现中,这将执行非常糟糕,并且永远不会接近最佳状态。
  • @Kevin,OP 没有使用“一些列表”。他毫不含糊地说这是ArrayList。据我所知,对于 Java 内置的所有列表,这将是 O(n)。这包括LinkedList
【解决方案4】:

我认为创建一个仅包含第一个元素的新 ArrayList 会更快。类似:

E temp = mapOverlays.get(0);
mapOverlays = new ArrayList<E>().add(temp);

【讨论】:

  • 顺便说一句,Daniel 的建议可能更好,因为它不会创建新对象。所以对对象的引用仍然存在。
  • add返回一个boolean,所以你不能做mapOverlays = new ArrayList&lt;E&gt;().add(temp);你需要两个语句,mapOverlays = new ArrayList&lt;E&gt;();mapOverlays.add(temp);
【解决方案5】:

ArrayList 具有从 0 到 size() - 1 的整数索引。你可以这样做:

int size = mapOverlays.size();
for(int n=1;n<size;n++)
{
    mapOverlays.remove(1);
}

这可能符合您对 PHP 的期望。它通过不断删除第一个元素来工作,该元素会发生变化。但是,这样做的性能很差,因为内部阵列必须不断地向下移动。最好使用clear() 或者倒序使用。

太糟糕了removeRange被保护了,因为这对于这种类型的操作会很方便。

【讨论】:

  • +1 用于指出潜在解决方案的性能劣势。另外...请记住,您始终可以扩展 ArrayList 并公开任何受保护的方法。
  • 您不需要removeRange(问题不在于它受到保护,而在于它甚至不存在于List 接口上(这是正确的))。请参阅 Adam Crune 的回答。
  • @Kevin,OP 没有使用List 接口,所以这是不合理的。你可以争辩说他应该这样做,但也许他确信他明确地想要一个基于数组的类,因为它的性能特征。
【解决方案6】:

简单。

mapOverlays = Collections.singletonList(mapOverlays.get(0));

【讨论】:

  • 也许不是 OP 想要的 - 结果列表只有第一个元素,但你不能再添加任何东西了。所以这不是一个错误的答案,但它引入了一些限制。
【解决方案7】:

如果您使用java.util.List 实现而不是数组,则每次删除某些内容并且n+1 项替换n 项时数组的大小都会变小。当n 大于列表中的最后一个索引时,此代码最终将生成ArrayIndecOutOfBoundsException

Java 也有一个数组类型,它的大小不能改变:

Object[] mapOverlay = //initialize the array here
int size = mapOverlay.length;
for(int n=1;n<size;n++)
{
    mapOverlay[n] = null;
}

我不了解 PHP,但这听起来很接近您所追求的行为。但是,List 实现比数组更灵活、更舒适。

编辑:这是List.remove(int) 的Javadoc 的链接:http://java.sun.com/javase/6/docs/api/java/util/List.html#remove%28int%29

【讨论】:

    【解决方案8】:
    【解决方案9】:

    使用while循环删除第一个元素之后的所有内容:

    while (mapOverlays.size() > 1) {
        mapOverlays.remove(1);
    }
    

    编辑(见 Adam Crume 的评论)

    如果性能有问题,你应该使用这个

    while (mapOverlays.size() > 1) {
        mapOverlays.remove(mapOverlays.size()-1);
    }
    

    甚至有点微优化

    int last = mapOverlays.size() - 1;
    while (last >= 1) {
        mapOverlays.remove(last);
        last -= 1;
    }
    



    如果性能确实是个问题(并且列表中有很多元素),您应该使用sublist 解决方案。阅读起来有点困难,但如果无法重新创建列表实例(在别处引用),这可能是最快的解决方案。

    【讨论】:

    • 对于 ArrayList,这将执行非常糟糕 - O(n^2) 时间 - 因为它必须调用 System.arraycopy 几乎整个数组 n-1 次。删除最后一个元素而不是索引 1 处的那个,应该会好很多。
    • @Adam - 正确,答案已编辑,也许 remove(1) 解决方案仍然比 O(n^2) 更糟糕,但我更喜欢它用于更易读的小列表(IMO) -问题根本没有提到性能。 sublist 解决方案优雅且更好(最好的),但并不是每个人都了解sublist 的工作原理。
    • 我不在乎人们是否不使用子列表。我只是认为将运行时间从 O(n^2) 减少到 O(n) 值得为可读性做出一点牺牲。 remove(1) 解决方案可能适用于小列表,但我认为最好有适用于任何列表的代码。
    【解决方案10】:
    int size = mapOverlays.size();
    for(int n=0;n<size;n++)
    {
        mapOverlays.remove(n);
    }
    

    在 java 中,如果 mapOverlays 是列表,那么它以 0 作为第一个索引开始。所以在 for 循环中 n=0。

    【讨论】:

    • 我认为 OP 希望保留列表中的第一个元素并删除其他所有元素。
    【解决方案11】:

    因为在一个 ArrayList 第一个元素的索引为 0
    在 Java 中正确的方法是:

    while( mapOverlays.size() > 1 ) {
      mapOverlays.remove( mapOverlays.size() - 1 );
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-05-15
      • 1970-01-01
      • 2016-07-23
      • 1970-01-01
      • 2023-02-07
      • 2017-01-23
      • 2019-08-01
      相关资源
      最近更新 更多