我有一个HashSet,其中有10000个元素。我想从该HashSet中提取随机的100个元素。所以我认为我可以在套装上使用shuffle,但它不起作用。
Set<String> users = new HashSet<String>();
// for randomness, but this doesn't work
Collections.shuffle(users, new Random(System.nanoTime()));
// and use for loop to get 100 elements
我现在不能使用shuffle,还有其他最好的方法可以从Java中的HashSet中获取100个随机元素吗?
答案 0 :(得分:6)
对集合进行混洗意味着元素中存在一些已定义的元素顺序,因此元素可以重新排序。 HashSet
不是有序集合,因为内部没有元素的顺序(或者说排序的细节不会暴露给用户)。因此,实施起来,对HashSet
进行洗牌没有多大意义。
您可以做的是将set
中的所有元素添加到ArrayList
,随机播放并获得结果。
List<String> usersList = new ArrayList<String>(users);
Collections.shuffle(usersList);
// get 100 elements out of the list
答案 1 :(得分:6)
如果不构建新列表,您可以实现以下算法:
n = 100
d = 10000 # length(users)
for user in users:
generate a random number p between 0 and 1
if p <= n / d:
select user
n -= 1
d -= 1
当你遍历列表时,你会降低概率 通过减少n来选择未来的元素,但是在 同时通过减少d来增加概率。原来, 你将有100/10000的机会选择第一个元素。 如果你决定采取这个元素,你将有99/999的机会 选择第二个元素;如果你不采取第一个,你会 选择第二个元素的机会稍微好一点。数学计算结果是,最终,每个元素都有100/10000的机会被选为输出。
答案 2 :(得分:-1)
java.lang.HashSet有一个订单,因此您无法对集合进行随机播放。如果必须使用集合,则可以迭代集合并在随机位置停止。
伪代码:
Set randomUsers = new HashSet<String>();
Random r = new Random();
Iterator it = users.iterator();
numUsersNeeded = 100;
numUsersLeft = users.size();
while (it.hasNext() && randomUsers.size() < 100) {
String user = it.next();
double prop = (double)numUsersNeeded / numUsersLeft;
--numUsersLeft;
if (prop > r.nextDouble() && randomUsers.add(user)) {
--numUsersNeeded;
}
}
你可能会重复这一点,因为没有你可以获取100个元素的garantiy。
如果内存没有问题,你可以创建一个数组并选择100个随机元素:
伪代码II:
Object userArray[] = user.toArray();
Set<String> randoms = new HashSet<String>();
while(randoms.size() != 100) {
int randomUser = userArray[new Random().nexInt(10000)];
randoms.add(randomUser);
}