警告這個答案是唯一的實驗使用。對於真正的項目你可能應該使用自己的集合類型。
所以我在HashSet source做了一些研究,我認爲很少有機會在不違反封裝的情況下提取最有價值的class HashTrieSet
的內部結構。
我沒有想出這個代碼,這是延長Ben Reich's solution:
package scala.collection
import scala.collection.immutable.HashSet
import scala.util.Random
package object random {
implicit class HashSetRandom[T](set: HashSet[T]) {
def randomElem: Option[T] = set match {
case trie: HashSet.HashTrieSet[T] => {
trie.elems(Random.nextInt(trie.elems.length)).randomElem
}
case _ => Some(set.size) collect {
case size if size > 0 => set.iterator.drop(Random.nextInt(size)).next
}
}
}
}
文件應在src/scala/collection/random
文件夾中的某處創建
注意scala.collection
包 - 這件事情使得HashTrieSet
的elems
部分可見。這只是我能想到的解決方案,它可以比O(n)
更好地運行。當前版本的複雜程度應該爲immutable.HashSet
的任何操作。
另一個警告 - 的HashSet
私人結構不Scala的標準庫API的一部分,所以它可以改變任何版本進行這項代碼錯誤(儘管它並沒有因爲2.8改變)
這是'mutable.HashSet'或者你正在使用的'immutable.HashSet'? – Odomontois
我懷疑在集合上直接使用迭代器,並且在0和集合的大小之間隨機推進它可能會比轉換爲List更好,但我不知道大小或迭代器的實現是什麼在HashSet上,所以我不確定。 –
實際上我用'Random.shuffle(h).headOption'提出的解決方案是完全錯誤的,它總是返回相同的結果 – kosii