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

问题描述

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

例如,给定数组:

const arr = [1,2,3,4,5,6,7,8];

例如,调用sample(arr,2)会返回[[7,8],[4,5],[2,3]]调用sample(arr,4)必然会返回[[1,4],[5,8],而调用sample(arr,2)会引发错误

编辑-也许在最初的问题中并不清楚:样本应该是连续元素的列表。例如,这就是sample(arr,4)只能返回[[1,8]而不能返回[[2,1,6],8]的原因。

解决方法

您可以使用贪婪算法,并从混洗后的数组中提取m个n元组:

const arr = [2,1,3,4,5,6,7,8];
function sample(arr,length,size){
  if(arr.length < length*size)
    throw new Error("too short");
  arr.sort(() => Math.random() - 0.5);
  let res = [];
  for(let i = 0; i < length; i++) res.push(arr.slice(i*size,i*size+size));
  return res;
}
console.log(sample(arr,2,4));

,

您可以首先创建一个具有返回值格式的列表:

               WRITE (2,'(a,9e10.3)') 'JC1 ',xk,xtd2 (j,jj),x8,jj2),cl,jj5),xkcheck,jj3),jj4)

               IF (ABS (1.0 - (xk / xtd2 (j,jj))) < tolkn) THEN 
                   IF (ABS (x8 - xtd2 (j,jj2)) < tolerance .AND. ABS (cl - xtd2 (j,jj5)) < tolerance) THEN
                       IF (ABS (xkcheck - xtd2 (j,jj3)) < tolerance) THEN
                           IF (iconcrete .EQ. INT (xtd2 (j,jj4))) jmx = j ! jmx is assigned the index of a matching material (within tolerance)
                       END IF
                   END IF
               END IF

可以使用以下长度写出这些格式数组:

[ 1,8]
[<---->,<---->,<>,<>] // sample(array,2)
[<------------>,<------------>] // sample(array,4)

然后将格式数组改组以获得随机样本选择:

[1,8]
[   2,1] // sample(array,2)
[         4,4] // sample(array,4)

然后对于格式数组的每个元素,从输入数组中删除前[1,4) 个元素。然后存储它们,除非它是填充符(将一个大小的块放入以达到数组长度)。

n

最后将产生的样本洗牌。

[1,8]
[[1,2],[4,5],[6,7]]  // sample(array,2)
[[1,4],[5,8]] // sample(array,4)

[1,8]
[[4,[1,2)
[[5,8],4]] // sample(array,4)

请注意,const arr = [1,8]; console.log(sample(arr,2)); console.log(sample(arr,4)); console.log(sample(arr,2)); function randomInt(limit) { return Math.floor(Math.random() * limit); } function shuffle(array) { for (let limit = array.length; limit > 0; --limit) array.push(...array.splice(randomInt(limit),1)); } function sample(array,sampleCount,sampleLength) { let elementCount = sampleCount * sampleLength; if (elementCount > array.length) throw "invalid sampleCount/sampleLength arguments"; const filler = {valueOf: () => 1}; const fillerCount = array.length - elementCount; const lengths = Array.from( {length: sampleCount + fillerCount},(_,i) => i < sampleCount ? sampleLength : filler ); shuffle(lengths); const samples = Array.from(array); for (const length of lengths) { const sample = samples.splice(0,length); if (length === filler) continue; samples.push(sample); } shuffle(samples); return samples; }===中很重要。如果您使用length === filler,则==也将等于filler。然后,这将与诸如每个样本长度为1的{​​{1}}之类的调用冲突。

sample(array,1)

,

我认为最好的实现将首先洗牌。这是我的两分钱:

function shuffle(array){
  let a = array.slice(),i = a.length,n,h;
  while(i){
    n = Math.floor(Math.random()*i--); h = a[i]; a[i] = a[n]; a[n] = h;
  }
  return a;
}
function sample(array,chunks,count){
  const r = [],a = shuffle(array);
  for(let n=0; n<chunks; n++){
    r.push(a.splice(0,count));
  }
  return r;
}
const arr = [1,2)); console.log(sample(arr,4));

,

您可以轻松地使用Rando.js(这是加密安全的),mapsplice来完成此操作。只需使用randojs的randoSequence函数将提供的数组改组并在改组后的数组中拼接n size-m数组即可获得我们需要返回的所有内容。如果所提供的数组的值太少,则我们返回的后面的数组将更短。

function sample(arr,m){
  arr = randoSequence(arr).map(i => i.value),sample = [];
  for(var i = 0; i < n; i++) sample[i] = arr.splice(-m);
  return sample;
}

console.log(sample([1,2));
<script src="https://randojs.com/2.0.0.js"></script>