34

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

我有 Guava 可用,但我不需要使用它。

4

7 回答 7

40

不确定性能,但您可以使用 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);
于 2012-04-27T16:23:03.900 回答
12

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

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

顺便说一句,从 JDK 10 开始,Collectors还允许累积到不可变类型(与静态工厂创建的类型相同Set.of()):

Stream.concat(oldSet.stream(),
              Stream.of(singleElement))
      .collect(Collectors.toUnmodifiableSet())
于 2020-03-30T16:15:27.913 回答
7

你可以考虑 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 & java.util.Collections)

于 2012-04-29T03:23:20.050 回答
3

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

于 2012-04-27T16:22:19.557 回答
3

你有三个选择。

  • 使用可变集合。
  • 检查元素不存在,如果不存在,则创建集合的副本并添加元素。
  • 创建一个包含前一个集合和元素的包装集。

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

于 2012-04-27T16:23:32.223 回答
0

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

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

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

于 2016-10-27T13:03:31.853 回答
-1

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

于 2012-04-27T16:22:56.483 回答