Javascript 从数组中获取n个非重叠的m大小的样本

Javascript 从数组中获取n个非重叠的m大小的样本,javascript,arrays,random,sample,Javascript,Arrays,Random,Sample,给定一个数组,如何从中提取大小为m的n非重叠随机样本 例如,给定数组: const arr = [1, 2, 3, 4, 5, 6, 7, 8]; 调用sample(arr,3,2)将返回[[7,8],[4,5],[2,3],调用sample(arr,2,4)将必然返回[[1,2,3,4],[5,6,7,8],调用sample(arr,5,2)将抛出错误 编辑-可能这在最初的问题中不清楚:示例应该是连续元素的列表。这就是为什么sample(arr,2,4)只能返回[[1,2,3,4],[5,6

给定一个数组,如何从中提取大小为
m
n
非重叠随机样本

例如,给定数组:

const arr = [1, 2, 3, 4, 5, 6, 7, 8];
调用
sample(arr,3,2)
将返回
[[7,8],[4,5],[2,3]
,调用
sample(arr,2,4)
将必然返回
[[1,2,3,4],[5,6,7,8]
,调用
sample(arr,5,2)
将抛出错误


编辑-可能这在最初的问题中不清楚:示例应该是连续元素的列表。这就是为什么
sample(arr,2,4)
只能返回
[[1,2,3,4],[5,6,7,8]
而不是
[[2,3,1,6],[5,4,7,8]
,例如。

您可以使用贪婪算法,从无序数组中获取m大小的n个元组:

const arr=[2,1,3,4,5,6,7,8];
功能样本(arr、长度、大小){
if(阵列长度<长度*尺寸)
抛出新错误(“太短”);
arr.sort(()=>Math.random()-0.5);
设res=[];
对于(设i=0;iconsole.log(示例(arr,2,4));
我认为最好的实现应该先洗牌。这是我的两分钱:

函数洗牌(数组){
设a=array.slice(),i=a.length,n,h;
而(i){
n=Math.floor(Math.random()*i--);h=a[i];a[i]=a[n];a[n]=h;
}
返回a;
}
函数示例(数组、块、计数){
常数r=[],a=shuffle(数组);

对于(设n=0;n),您可以首先创建一个返回值格式的列表:

[ 1,  2,  3,  4,  5,  6,  7,  8]
[<---->, <---->, <---->, <>, <>] // sample(array, 3, 2)
[<------------>, <------------>] // sample(array, 2, 4)
然后洗牌格式数组以获得随机样本选择:

[1, 2, 3, 4, 5, 6, 7, 8]
[   2, 1,    2,    2, 1] // sample(array, 3, 2)
[         4,          4] // sample(array, 2, 4)
然后,对于format数组的每个元素,从输入数组中删除第一个
n
元素。然后存储它们,除非它是填充符(为达到数组长度而放入的一个大小的块)

最后洗牌产生的样本

[1, 2, 3, 4, 5, 6, 7, 8]
[[4,5], [1,2], [6,7]]  // sample(array, 3, 2)
[[5,6,7,8], [1,2,3,4]] // sample(array, 2, 4)
const arr=[1,2,3,4,5,6,7,8];
日志(样本(arr,3,2));
日志(示例(arr,2,4));
控制台日志(样本(arr,5,2));
函数randomInt(极限){
返回Math.floor(Math.random()*limit);
}
函数洗牌(数组){
for(让limit=array.length;limit>0;--limit)
array.push(…array.splice(randomInt(limit),1));
}
函数示例(数组、sampleCount、sampleLength){
让elementCount=sampleCount*sampleLength;
if(elementCount>array.length)
抛出“无效的sampleCount/sampleLength参数”;
常量填充={valueOf:()=>1};
常量fillerCount=array.length-elementCount;
const length=Array.from(
{length:sampleCount+fillerCount},
(u,i)=>i
您可以使用(加密安全的),而且非常简单。只需使用randojs的
randoSequence函数洗牌提供的数组,然后从洗牌后的数组中拼接出
n
size-
m
数组,即可获得我们需要返回的所有内容。如果提供的数组的值太少,我们返回的后面的数组将更短

函数示例(arr,n,m){
arr=randoSequence(arr).map(i=>i.value),sample=[];
对于(var i=0;i

如果您执行
sample(arr,20,40)
或甚至
sample(arr,5,2)
等操作,会发生什么情况?@Dominik可能会抛出一个错误,将进行编辑。
sample(arr,2,4)
也会返回
[[5,6,7,8],[1,2,3,4]
我在回答中假设会这样,因为
sample(arr,3,2)
返回
[7,8],[4,5],[2,3]
这似乎是一个随机采样顺序。@3limin4t0r是的,但这不是必要的步骤。最后的数组不需要洗牌。随机采样在哪里?@cabralpinto添加了一行来洗牌array@cabralpinto还有“不重叠”你的意思是你不会多次获取相同的值?此解决方案只获取前n个非重叠的m大小样本,而不是随机样本。是的,任何样本都不应包含与另一个样本相同的值。当然,除非数组有重复的值。非常喜欢这种方法。还学习了
{valueOf:()=>1}
技巧,非常有用。谢谢你的回答。如果你想创建自己的“复杂”数字,它很有用。当需要一个数字时,它会自动调用。例如,
4+complexObject
会调用
valueOf
函数来检索一个值。
[1, 2, 3, 4, 5, 6, 7, 8]
[[1,2], [4,5], [6,7]]  // sample(array, 3, 2)
[[1,2,3,4], [5,6,7,8]] // sample(array, 2, 4)
[1, 2, 3, 4, 5, 6, 7, 8]
[[4,5], [1,2], [6,7]]  // sample(array, 3, 2)
[[5,6,7,8], [1,2,3,4]] // sample(array, 2, 4)