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

时间:2012-04-27 16:19:14

标签: java guava

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

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

7 个答案:

答案 0 :(得分:32)

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

import com.google.common.collect.ImmutableSet

// ...
Set<Integer> newSet = new ImmutableSet.Builder<Integer>()
                                .addAll(oldSet)
                                .add(3)
                                .build();

当然你也可以为自己编写一个辅助方法:

public static <T> Set<T> setWith(Set<T> old, T item) {
  return new ImmutableSet.Builder<T>().addAll(old).add(item).build();
}

// ...
Set<Integer> newSet = setWith(oldSet, 3);

答案 1 :(得分:5)

您可以考虑Sets.union()。施工会更快,但使用速度会慢。

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

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

答案 2 :(得分:4)

您有三种选择。

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

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

答案 3 :(得分:4)

使用Java 8,您还可以使用流来实现这种效果

Stream.concat(oldSet.stream(),
              Stream.of(singleElement))
      .collect(toSet())

答案 4 :(得分:3)

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

答案 5 :(得分:0)

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

答案 6 :(得分:0)

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

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

这个answer有一个指向jdbm库的指针,因此值得查看jdbm:jdbm