web-dev-qa-db-ja.com

単一の要素を不変のセットに追加する効率的でエレガントな方法は何ですか?

不変セットがあります(Set<Integer>)多くの要素が含まれている可能性があります。そのセットの要素と1つの追加要素を含むコレクションが必要です。セットをコピーして要素を追加するための適切なコードが用意されていますが、可能な限り効率を維持する正しい方法を探しています。

Guavaを使用できますが、使用する必要はありません。

27
Max

パフォーマンスについてはわかりませんが、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);
35
Niklas B.

あなたは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)

5
Darren Gilroy

3つのオプションがあります。

  • 変更可能なセットを使用します。
  • セットのコピーを作成して要素を追加しない場合は、要素がまだ存在していないことを確認してください。
  • 前のセットと要素を含むラッパーセットを作成します。

値の分布によっては、BitSetSet<Integer>よりも適切な場合があります。

4
Peter Lawrey

セットが不変である場合、セットをコピーしてから新しい要素を追加する以外に、それを行う方法はありません。セットのコピーは、新しいセットを作成するときに基本セットをコンストラクター関数に渡すのと同じくらい簡単です。

3
hvgotcodes

フルコピーよりも優れたパフォーマンスが必要で、要素を順序付けする場合は、 B +ツリー の周りに効果的に不変のラッパーを使用して、優れたインクリメンタルセットのパフォーマンスを得ることができます。

B +ツリーにアイテムを追加するには、ImmutableSet.builder().addAll(...).add(...).build()。これは、n個の増分加算からセットを作成すると、O(sqr(n))ではなくO(n * log(n))になることを意味します。

この answer にはjdbmライブラリへのポインタがあるので、一見の価値があるかもしれません jdbm:jdbm

0
Mike Samuel

Java 8を使用すると、その効果のためにストリームを使用することもできます

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

同じ文で「不変」と「追加」を読んだときに、認知的不協和を経験しています。不変の値の可変コピーの最後に新しい要素を追加することはできますが、不変のセットを変更することはできません。エレガントなものは何も知りません。

0
duffymo