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


当前回答

如果您希望在Java中执行此操作,则应该考虑将元素复制到某种随机访问集合(例如ArrayList)中。因为,除非你的集合很小,否则访问所选元素的代价会很高(O(n)而不是O(1))。[ed: list copy也是O(n)]

或者,您可以寻找另一个更符合您需求的Set实现。来自公共集合的ListOrderedSet看起来很有前途。

其他回答

你能不能得到集合/数组的大小/长度,生成一个介于0和大小/长度之间的随机数,然后调用索引与该数字匹配的元素?HashSet有一个.size()方法,我很确定。

在伪代码中-

function randFromSet(target){
 var targetLength:uint = target.length()
 var randomIndex:uint = random(0,targetLength);
 return target[randomIndex];
}

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

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

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;
  }
}

如果你真的只想从Set中选择“任意”对象,而不保证随机性,最简单的方法是使用迭代器返回的第一个对象。

    Set<Integer> s = ...
    Iterator<Integer> it = s.iterator();
    if(it.hasNext()){
        Integer i = it.next();
        // i is a "random" object from set
    }

PHP,假设“set”是一个数组:

$foo = array("alpha", "bravo", "charlie");
$index = array_rand($foo);
$val = $foo[$index];

Mersenne Twister函数更好,但在PHP中没有与array_rand等效的MT函数。