将单个元素添加到不可变集合的有效且优雅的方法是什么?

我有一个不可变的集合(强制转换为Set ),可能包含许多元素。 我需要一个Collection,其中包含该集合中的元素以及一个额外元素。 我有kludgy代码来复制集合,然后附加元素,但我正在寻找尽可能保持高效的正确方法。

我有番石榴可用,但我不需要它。

不确定性能,但你可以使用Guava的ImmutableSet.Builder

 import com.google.common.collect.ImmutableSet // ... Set newSet = new ImmutableSet.Builder() .addAll(oldSet) .add(3) .build(); 

当然你也可以为自己写一个帮手方法:

 public static  Set setWith(Set old, T item) { return new ImmutableSet.Builder().addAll(old).add(item).build(); } // ... Set newSet = setWith(oldSet, 3); 

如果Set是不可变的,除了复制Set之外,我看不到任何其他方法,然后添加新元素。 请记住,复制集合就像在创建新集合时将基集传递给构造函数一样简单。

你有三个选择。

  • 使用可变集。
  • 检查元素是否已存在,如果没有创建集合的副本并添加元素。
  • 创建一个包含前一组和元素的包装器集。

有时, BitSet是比Set更好的选择,具体取决于值的分布。

您可以考虑Sets.union()。 构造会更快,但使用更慢。

 public static  Set setWith(Set old, T item) { return Sets.union(old, Collections.singleton(item); } 

(com.google.common.collect.Sets&java.util.Collections)

当我在同一个句子中读到“不可变”和“加法”时,我正在经历认知失调。 您可以在不可变值的可变副本的末尾添加新元素,但不能修改不可变集。 我不知道什么优雅。

如果您希望获得比完整副本更好的性能,并且对元素进行排序,则可以在B +树周围使用有效的不可变包装器来获得良好的增量集性能。

将项添加到B +树需要O(log(n))时间和增量分配,而不是使用ImmutableSet.builder().addAll(...).add(...).build()得到的O(n) ImmutableSet.builder().addAll(...).add(...).build() 。 这意味着从n增量添加构建集合是O(n * log(n)),而不是O(sqr(n))。

这个答案有一个指向jdbm库的指针,因此可能值得查看jdbm:jdbm