哪个Java集合允许廉价追加?

时间:2012-10-10 11:59:19

标签: java list

我在Java中搜索列表数据结构,允许廉价附加长列表。我尝试使用LinkedList,但我在addAll的文档中发现,迭代器用于附加两个列表。这意味着在操作期间克隆了附加的列表。迭代器遍历整个列表返回每个元素。是否有任何可用的集合在附加两个列表时省略了迭代?

10 个答案:

答案 0 :(得分:6)

您可以使用Guava's Iterables.concat方法创建连续的Iterable视图..

Iterable<T> combined = Iterables.concat(list1, list2);
  • 不会将元素从一个列表复制到另一个列表中。
  • 因此,不会更改您的任何列表..
  • 此外,这不会创建新列表(它创建的Iterable不是列表)

基本上它会创建一个Iterable,你可以通过它来重复迭代two列表(它从list1迭代元素然后从list2迭代..

注意: - 如果您想要一个列表作为two lists的串联,那么这可能对您没什么帮助..因为,它不会创建一个列表,但是一个Iterable ..对于这种情况,除了Iterating之外别无选择,而且copy每个引用都有...

来自docs: -

  

它将两个迭代组合成一个可迭代的。返回的可迭代   有一个遍历a中元素的迭代器,后跟   b中的元素。直到需要时才会轮询源迭代器。   返回的iterable的迭代器支持remove()   相应的输入迭代器支持它。

您还拥有此方法的 var-args版本 .. See Docs ..这可以使用任意数量的列表,并返回可以迭代这些列表的Iterables订单..所以,你可以这样做..

Iterable<T> combined = Iterables.concat(list1, list2, list3, list4, ...);

此链接 - &gt; google-guava-libraries-essentials也可能对您感兴趣..

答案 1 :(得分:5)

不是真的,因为所有“附加”操作都不对底层集合做任何假设。从技术上讲,可以直接附加两个链表,但附加必须是通用的,因此它使用迭代。

不允许直接连接的另一个好理由是,在追加更改后,一个列表也会影响另一个列表,我确信这不是理想的属性。

答案 2 :(得分:4)

ArrayList中的

addAll将其转换为数组,然后使用系统调用进行复制(System.arraycopy)。这应该比在java中循环更快,因为它是原生的,我不认为有一个廉价的appender。

答案 3 :(得分:3)

可能是addAll的ArrayList应该更快,因为它不迭代,但使用System.arrayCopy。代码看起来像

public boolean addAll(Collection<? extends E> c) {
    Object[] a = c.toArray();
        int numNew = a.length;
    ensureCapacity(size + numNew);  // Increments modCount
        System.arraycopy(a, 0, elementData, size, numNew);
        size += numNew;
    return numNew != 0;
    }

答案 4 :(得分:1)

  

这意味着在操作期间克隆了附加的列表。

创建迭代器不会克隆集合。

在大多数情况下,addAll方法调用toArray()以确保以原子方式提取数据,将数据集合的元素克隆为数组,这可能会使用迭代器来执行此操作。

  

是否有任何可用的集合在附加两个列表时省略了迭代?

不,但如果真的重要,你可以自己迭代这个集合。


效率最高的可能是

List<E> list1 = ... random access list ...
List<E> list2 = ... random access list ...

for(int i = 0; i < list2.size(); i++)
    list1.add(list2.get(i));

这不会创建任何对象,并且O(n)时间n是list2的大小。

答案 5 :(得分:0)

即使您确实找到了这样的集合类,也无法保证它将在未来的Java版本中继续以这种方式工作。那是因为这是一个未在Collection接口中指定的行为,因此受到类开发人员的一时兴起。

当然,您可以编写自己的集合类,但即使这样,您也会对其他集合类的行为做出假设

答案 6 :(得分:0)

addAllAbstractCollections方法的默认实现使用迭代器添加,但在提供自定义特定实现的子类中重写addAll方法

  • ArrayList使用System.arraycopy
  • LinkedList使用循环遍历元素。

答案 7 :(得分:0)

我认为标准API没有办法,但根据您的需要,您可以尝试自己实现。例如,您可以实现一个内部具有集合引用列表的集合,每次调用addAll方法时都会添加它。

答案 8 :(得分:0)

使用该行为,添加到第一个列表的列表将被消耗(即修改)或导致第二个列表成为具有各种陷阱的较大列表的子列表(如果您添加列表两次会发生什么... 。),

addAll有一个隐含的const参数(意味着第二个列表将在几次调用中保持不变),所以除非你自己滚动

,否则这种行为将不存在

答案 9 :(得分:0)

我只需要使用ArrayList,并愉快地添加All()我的东西。选择List实现如何执行addAll()操作,迭代或toArray都相对便宜并且它不太可能是性能瓶颈(假设您的应用程序 有用的工作)并不重要使用列表元素而不仅仅是创建列表......)。

如果你想要一个包含来自N个源列表的元素的独立列表,那么元素引用可以复制到某个地方(你可以改变) addAll()之后的源列表,但这不会影响conactinated列表,因此副本是不可避免的。)

如果你真的不需要需要 List语义(独立源代码),那么可以利用已经建议的Guava来创建多个列表的视图(或者滚动你自己,如果你不想要依赖,那就不是火箭科学。)