如何在同一循环中复制和随机化复制的元素?

时间:2016-12-14 04:27:35

标签: javascript arrays algorithm for-loop random

我尝试在数组中复制偶数,并在同一个for循环中随机化新复制的元素:

var arr=[0,1,2,3,4,5,6,7,8];
var arr2=[];
for(var i=0;i<arr.length;i++){
  if(arr[i]%2==0){
    arr2.splice(Math.random()*arr2.length,0,arr[i]);
  }
}
document.write(arr2);

概念很简单:将新复制的元素插入新数组的随机位置,但serval输出表明它不正确:

2,6,4,8,0
4,8,6,2,0
6,2,8,4,0

最后总是0。代码有什么问题?或者我的观念错了吗?

3 个答案:

答案 0 :(得分:1)

这是一个scopedShuffle函数:

function scopedShuffle(a){
  var n = a.slice(), l = n.length;
  n.sort(function(b, c){
    return 0.5 - Math.floor(Math.random()*(l+1))/l;
  });
  return n;
}
van resultArray = scopedShuffle(yourArrayHere);

这里的关键是使用n var n = a.slice()的范围,这样就不会改变原始数组。

我会使用Constuctor:

&#13;
&#13;
function ShuffleMaster(inputArray){
  var a = inputArray;
  if(!(a instanceof Array)){
    throw new Error('inputArray must be an Array');
  }
  this.getInputArray = function(){
    return a;
  }
  this.setInputArray = function(inputArray){
    if(!(inputArray instanceof Array)){
      throw new Error('inputArray must be an Array');
    }
    a = inputArray;
    return this; // allows for daisy-chaining
  }
  this.shuffle = function(){
    var n = a.slice(), l = n.length;
    n.sort(function(b, c){
     return 0.5 - Math.floor(Math.random()*(l+1))/l;
    });
    return n;
  }
}
var myArray = [0, 7, 21, 26, 78, 756];
var sM = new ShuffleMaster(myArray);
console.log(sM.shuffle()); console.log(sM.shuffle());
console.log(sM.setInputArray([4, 5, 85, 46, 11]).shuffle());
console.log(sM.getInputArray());
&#13;
&#13;
&#13;

这里是一个简单的闭包样式,其中自执行函数对新数组进行范围限定,因此可以在下次调用时访问它而不传递原始参数...几乎是静态的。

&#13;
&#13;
var scopedShuffle = (function(){
  var a;
  return function(inputArray){
    if(inputArray){
      a = inputArray.slice();
    }
    var n = a.slice(), l = n.length;
    n.sort(function(b, c){
      return 0.5 - Math.floor(Math.random()*(l+1))/l;
    });
    return n;
  }
})();
console.log(scopedShuffle(['a', 2, 4, 'g', 'apes']));
console.log(scopedShuffle()); console.log(scopedShuffle());
console.log(scopedShuffle(['learning', 'you', 'now', 'are', 'monkeys', 42, 'life', 'itself', 'the Universe']));
console.log(scopedShuffle()); console.log(scopedShuffle());
&#13;
&#13;
&#13;

答案 1 :(得分:0)

Math.random()会返回介于0和0之间的数字独占。这意味着Math.random()*arr2.length总是而不是arr2.length,因此任何元素都不会被拼接到数组的末尾 - 除了在循环的第一次迭代时数组为空,因此0最终成为其第一个也是唯一的元素。但是后续迭代会在除结尾之外的任何位置插入随机位置,因此始终将0推向右侧。

您可以将Math.random()*arr2.length更改为Math.random() * (arr2.length + 1)

来解决此问题

另请注意.splice()似乎并不关心您是否传递了一个不是整数的数字,但为了整洁,我更倾向于使用Math.floor(Math.random() * (arr2.length + 1))

演示:

&#13;
&#13;
function makeArray() {
  var arr=[0,1,2,3,4,5,6,7,8];
  var arr2=[];
  for(var i=0;i<arr.length;i++){
    if(arr[i]%2==0){
      arr2.splice(Math.floor(Math.random()*(arr2.length+1)), 0, arr[i]);
    }
  }
  return arr2;
}
                  
console.log(JSON.stringify(makeArray()));
console.log(JSON.stringify(makeArray()));
console.log(JSON.stringify(makeArray()));
console.log(JSON.stringify(makeArray()));
console.log(JSON.stringify(makeArray()));
console.log(JSON.stringify(makeArray()));
console.log(JSON.stringify(makeArray()));
&#13;
&#13;
&#13;

答案 2 :(得分:0)

简单解决方案:长链方法(slicefiltersort)。

首先使用.slice(0)进行克隆,然后.filter()过滤掉奇数,最后使用.sortMath.random()进行随机播放。

var arr2 = arr.filter(function(a) {
  return (a % 2) === 1; // Return true if a is even
}).sort(function() {
  return 0.5 - Math.random();
};

参见示例:

&#13;
&#13;
function shuffleIt() {
  var arr = document.getElementById('numberlist').value.split(' ');
  var arr2 = arr.filter(function(a){return a%2 === 0}).sort(function(){return 0.5-Math.random()});
  document.getElementById('output').innerHTML = arr2.join(',');
}
&#13;
Type a list of numbers (separate with spaces)
<input type="text" id="numberlist" value="1 2 3 4 5 6 7 8"/>
<button onclick="shuffleIt()">Shuffle evens (click multiple times to get different results) </button>
<br/>
<b>Output:</b>
<div id="output"></div>
&#13;
&#13;
&#13;

详细说明:

  1. .filter()调用在数组的每个元素上传递给它的回调函数。如果函数返回true,则保留元素;如果为false,则删除它。 a % 2 === 0是检查a是否为偶数的条件,因此这将删除所有非偶数。此方法不会改变数组,而是返回一个新数组。
      

    filter()方法创建一个新数组,其中包含通过所提供函数实现的测试的所有元素。

  2. https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/filter

    1. .sort对数组进行排序。它一次比较两个项目,使用从ma函数返回的数字的符号决定哪一个项目在另一个项目之前:
    2.   

      如果compareFunction(a,b)小于0,则将a排序为低于b的索引,即a先到先得。   如果compareFunction(a,b)[传入的回调函数]返回0,则保持a和b相对于彼此保持不变,但是对于所有不同的元素进行排序。注意:ECMAscript标准不保证这种行为,因此并非所有浏览器(例如可追溯到至少2003年的Mozilla版本)都尊重这一点。   如果compareFunction(a,b)大于0,则将b排序为低于a的索引。   当给定一对特定元素a和b作为其两个参数时,compareFunction(a,b)必须始终返回相同的值。如果返回不一致的结果,则排序顺序未定义。

      https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort

      如您所见,返回数字的符号决定了首先出现的数组项。 (0.5-Math.random())随机返回正数或负数(技术上可能为0,但非常不可能),因此随机排序数组。 注意:此函数会改变数组,但我们使用.filter()创建了一个新数组,因此原始数据仍未改动。