Java中从ArrayList进行无重复抽样

6
我有一个包含30个元素的ArrayList。我想从这个列表中创建许多包含15个元素的子列表。有什么高效的方法吗?
目前,我克隆了ArrayList并使用remove(random)来完成此操作,但我确信这太笨拙了。我应该做些什么呢?Java是否有像R中的“sample”函数?
澄清:无重复抽样是指从原始列表中随机选择15个唯一元素。此外,我希望能够反复执行此操作。

请具体说明一下。您是要随机子集,还是有其他的标准? - cheeken
你的意思是什么?你想创建包含15个随机项目的子列表,还是在30个项目的集合中创建所有15个项目的(唯一)排列组合? - Savino Sguera
4个回答

17
使用Collections#shuffle方法打乱您的原始列表,并返回一个包含前15个元素的列表。

这是目前最有效的无重复抽样方法。 - Brent Worden
迄今为止最简单的方法! - Brendan Hill

2

考虑创建新的列表并添加当前列表中的随机元素,而不是复制所有元素并删除它们。

另一种方法是在当前列表上创建某种类型的View(视图)。

实现 Iterator(迭代器)接口,在next(下一个)操作期间随机生成元素索引,并从当前列表中按索引检索元素。


但是如果我在调用next()时随机生成索引,我就无法获得唯一的元素。 - CarrKnight
最简单的方法是将先前生成的索引存储在 HashSet 中。 - Mairbek Khadikov

1
不,Java没有像R中的样本函数那样的示例函数。但是,可以编写这样的函数:
// Samples n elements from original, and returns that list
public <T> static List<T> sample(List<T> original, int n) {
    List<T> result = new ArrayList<T>(n);
    for (int i = 0; i < original.size(); i++) {
        if (result.size() == n)
            return result;
        if ((n - result.size()) >= (original.size() - i)) {
            result.add(original.get(i));
        } else if (Math.random() < ((double)n / original.size())) {
            result.add(original.get(i));
        }
    }

    return result;
}

该函数遍历original,并根据随机数将当前元素复制到result中,除非我们接近original的末尾需要复制所有剩余的元素(循环中的第二个if语句)。

我喜欢它,但我担心不是每个元素被选择的机会都是相等的。 - CarrKnight

0
这是一个基本的组合数学问题。你有一个包含30个元素的列表,你想选择其中的15个。如果顺序很重要,你需要排列,如果顺序不重要,你需要组合。
网上有各种Java组合数学示例,它们通常使用combinadics。我不知道是否有现成的Java库,但Apache Math Commons提供二项式系数支持,可以帮助你实现combinadics。一旦你有了从0到29的15个索引序列,我建议创建一个只读迭代器,以便你可以从中读取元素。这样你就不必创建任何新列表或复制任何引用。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接