2012-04-27 23 views
19

我有一個不可變的集合(投射爲Set<Integer>),可能包含許多元素。我需要一個集合,其中包含來自該集合的元素以及一個附加元素。我有適當的代碼來複制集合,然後追加元素,但我正在尋找能夠使事物儘可能高效的正確方法。將單個元素添加到不可變集合的高效優雅方法是什麼?

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

回答

28

不確定的表現,但你可以用番石榴的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); 
3

如果Set是不可變的,除了複製Set,然後添加新的元素外,我沒有看到任何其他方法。記住,複製一個集合就像在創建新集合時將基本集合傳遞給構造函數一樣簡單。

+0

我認爲這是暗示的;問題是關於如何實現這一點。 – sdgfsdh 2017-05-22 11:16:43

2

當我在同一個句子中讀到「不可變」和「添加到」時,我正在經歷認知失調。您可以將新元素添加到不可變值的可變副本的末尾,但不能修改不可變集。我不知道任何優雅。

3

你有三個選擇。

  • 使用可變集合。
  • 檢查元素是否已經存在,如果沒有創建該集合的副本並添加元素。
  • 創建一個包含前一組和元素的包裝集。

有時BitSet是根據您的值的分佈比Set<Integer>一個更好的選擇。

+0

不能使用可變集 - 我不控制返回值的API。檢查它不存在是一個很好的建議。謝謝。 – Max 2012-04-27 16:30:18

+0

該檢查與副本的成本相比很快。 – 2012-04-27 16:31:47

+0

建築商不會檢查它是否已經存在嗎?我的意思是在分配副本之前。 – jmg 2012-05-13 11:16:07

3

你可能會考慮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中)

0

當您希望自己的完整副本更好的性能,你必須在元素的排序,你可以使用爲了獲得良好的增量集性能,圍繞B+ tree有效地不可變的包裝。

將項目添加到B +樹需要O(log(n))時間和增量分配,而不是O(n),因爲您使用ImmutableSet.builder().addAll(...).add(...).build()。這意味着從n增量增加構建一個集合是O(n * log(n)),而不是O(sqr(n))。

answer有一個指向jdbm庫的指針,所以它可能值得看看jdbm:jdbm

相關問題