如何从集合中随机选取一个元素? 我特别感兴趣的是从a中随机选取一个元素 Java中的HashSet或LinkedHashSet。 也欢迎其他语言的解决方案。


当前回答

以霍斯的答案为起点的通用解决方案。

/**
 * @param set a Set in which to look for a random element
 * @param <T> generic type of the Set elements
 * @return a random element in the Set or null if the set is empty
 */
public <T> T randomElement(Set<T> set) {
    int size = set.size();
    int item = random.nextInt(size);
    int i = 0;
    for (T obj : set) {
        if (i == item) {
            return obj;
        }
        i++;
    }
    return null;
}

其他回答

这与接受的答案(Khoth)相同,但删除了不必要的size和i变量。

    int random = new Random().nextInt(myhashSet.size());
    for(Object obj : myhashSet) {
        if (random-- == 0) {
            return obj;
        }
    }

尽管去掉了前面提到的两个变量,但上面的解决方案仍然是随机的,因为我们依赖于随机(从随机选择的索引开始)在每次迭代中将自己递减到0。

c++。这应该是相当快的,因为它不需要遍历整个集合,也不需要对它排序。这应该适用于大多数现代编译器,假设它们支持tr1。如果没有,您可能需要使用Boost。

Boost文档有助于解释这一点,即使你不使用Boost。

诀窍在于利用数据已被划分为多个bucket的事实,并快速识别随机选择的bucket(具有适当的概率)。

//#include <boost/unordered_set.hpp>  
//using namespace boost;
#include <tr1/unordered_set>
using namespace std::tr1;
#include <iostream>
#include <stdlib.h>
#include <assert.h>
using namespace std;

int main() {
  unordered_set<int> u;
  u.max_load_factor(40);
  for (int i=0; i<40; i++) {
    u.insert(i);
    cout << ' ' << i;
  }
  cout << endl;
  cout << "Number of buckets: " << u.bucket_count() << endl;

  for(size_t b=0; b<u.bucket_count(); b++)
    cout << "Bucket " << b << " has " << u.bucket_size(b) << " elements. " << endl;

  for(size_t i=0; i<20; i++) {
    size_t x = rand() % u.size();
    cout << "we'll quickly get the " << x << "th item in the unordered set. ";
    size_t b;
    for(b=0; b<u.bucket_count(); b++) {
      if(x < u.bucket_size(b)) {
        break;
      } else
        x -= u.bucket_size(b);
    }
    cout << "it'll be in the " << b << "th bucket at offset " << x << ". ";
    unordered_set<int>::const_local_iterator l = u.begin(b);
    while(x>0) {
      l++;
      assert(l!=u.end(b));
      x--;
    }
    cout << "random item is " << *l << ". ";
    cout << endl;
  }
}

Perl 5

@hash_keys = (keys %hash);
$rand = int(rand(@hash_keys));
print $hash{$hash_keys[$rand]};

这里有一种方法。

既然你说“其他语言的解决方案也欢迎”,下面是Python的版本:

>>> import random
>>> random.choice([1,2,3,4,5,6])
3
>>> random.choice([1,2,3,4,5,6])
4

在lisp中

(defun pick-random (set)
       (nth (random (length set)) set))