我在Java中搜索列表数据结构,允许廉价附加长列表。我尝试使用LinkedList,但我在addAll的文档中发现,迭代器用于附加两个列表。这意味着在操作期间克隆了附加的列表。迭代器遍历整个列表返回每个元素。是否有任何可用的集合在附加两个列表时省略了迭代?
答案 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)
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)
addAll
中AbstractCollections
方法的默认实现使用迭代器添加,但在提供自定义特定实现的子类中重写addAll
方法
像
System.arraycopy
答案 7 :(得分:0)
我认为标准API没有办法,但根据您的需要,您可以尝试自己实现。例如,您可以实现一个内部具有集合引用列表的集合,每次调用addAll方法时都会添加它。
答案 8 :(得分:0)
使用该行为,添加到第一个列表的列表将被消耗(即修改)或导致第二个列表成为具有各种陷阱的较大列表的子列表(如果您添加列表两次会发生什么... 。),
addAll有一个隐含的const参数(意味着第二个列表将在几次调用中保持不变),所以除非你自己滚动
,否则这种行为将不存在答案 9 :(得分:0)
我只需要使用ArrayList,并愉快地添加All()我的东西。选择List实现如何执行addAll()操作,迭代或toArray都相对便宜并且它不太可能是性能瓶颈(假设您的应用程序 有用的工作)并不重要使用列表元素而不仅仅是创建列表......)。
如果你想要一个包含来自N个源列表的元素的独立列表,那么元素引用有可以复制到某个地方(你可以改变) addAll()之后的源列表,但这不会影响conactinated列表,因此副本是不可避免的。)
如果你真的不需要需要 List语义(独立源代码),那么可以利用已经建议的Guava来创建多个列表的视图(或者滚动你自己,如果你不想要依赖,那就不是火箭科学。)