java - 如何仅使用每个类的元素数量进行抽样而不进行替换?
问题描述
我有一个字符串(["A", "B", ...])
列表和一个尺寸列表([4,7,...])
。我想从最初i
出现位置字符串的字符串集中进行采样而不进行替换sizes[i]
。我必须执行此操作k
次数。显然,如果我选择 string i
,则sizes[i]
减 1。我开发的当前简单的解决方案是生成整个输入集,将其打乱,然后迭代地弹出数组的第一个元素。这显然是低效的,因为如果一个字符串出现 100 万次,我将不得不生成 100 万个条目。
public static void main(String[] args) {
String[] elems = { "A", "B", "C", "D", "E" };
Integer[] sizes = { 10, 5, 4, 7, 3 };
int k = 3;
ArrayList<String> bag = new ArrayList<>();
for (int i = 0; i < elems.length; i++) {
for (int j = 0; j < sizes[i]; j++) {
bag.add(elems[i]);
}
}
Collections.shuffle(bag);
for (int i = 0; i < k; i++) {
System.out.println(bag.remove(0));
}
}
有没有更好更有效的方法来执行这个操作?谢谢。
解决方案
假设袋子不必是持久的或根本不需要使用,您可以创建一个包含输入和频率的类,例如像这样(简化):
class SampleElement<T> {
private T value;
private int frequency;
//constructors, getters, setters
}
然后从您拥有的输入中构建这些元素的集合,例如(再次简化):
List<SampleElement<String>> samples = Arrays.asList(new SampleElement<String>("A",10), ...);
最后循环直到该集合为空,或者您已经完成了k
多次并选择一个随机元素。降低该元素的频率,如果它达到 0,则将其从集合中删除。示例(在我的脑海中,因此可能包含错误):
Random rand = new Random();
int runs = k;
while(runs > 0 && !samples.isEmpty() ) {
runs--;
int index = rand.nextInt(samples.size());
SampleElement<String> element = samples.get(index);
System.out.println(element.getValue());
element.decrementFrequency();
if( element.getFrequency() <= 0 ) {
samples.remove(index);
}
}
推荐阅读
- net-http - Ruby 3 net-http:如何编码查询参数以匹配 Open Page Rank 示例中的参数?
- web3js - 何时/何处定义 web3.eth.defaultAccount?
- handlebars.net - Handlebars.net:在块表达式“货币”关闭之前到达模板的末尾
- node.js - 如何在 AWS Lambda 上工作的 docker 映像中获取 headless chrome (Puppeteer)
- java - 高分二进制文件
- node.js - 为什么 npm i 无法完成安装?为什么它告诉 node 和 npm 是无效命令?
- angularjs - setValidation 时应用角度摘要
- r - 如何在 r 中将 9 列重新排列为 3?
- amazon-web-services - AWS - 地理位置标头 - CloudFront - LambdaEdge - S3 存储桶方案不起作用
- javascript - TypeScript - 类型“布尔”不满足返回布尔值的类型的约束