0

Say I have an array in javascript like

[[1,2,3],[4,5,6],[7,8,9],[10,11,12],[13,14,15],[16,17,18]]

Can I random shuffle the elements of subarrays to get something like this

[[16,4,10],[8,3,9],[1,14,18],[2,5,7],[6,17,11],[12,13,15]]

EDIT: All the subarrays are of same length. And the new array will have subarrays of the same length as the old one.

devcoder
  • 1,675
  • 2
  • 21
  • 28

5 Answers5

2

I would use underscore for this: http://underscorejs.org/

v = [[1,2,3],[4,5,6],[7,8,9],[10,11,12],[13,14,15],[16,17,18]]
v2 = _.shuffle(_.flatten(v))
v3 = _.groupBy(v2, function(item, i) {
  return i % v.length;
})

ilan berci
  • 3,883
  • 1
  • 16
  • 21
1
function arrayShuffle(){
  var tmp, rand;
  for(var i =0; i < this.length; i++){
    rand = Math.floor(Math.random() * this.length);
    tmp = this[i]; 
    this[i] = this[rand]; 
    this[rand] =tmp;
  }
}

Array.prototype.shuffle =arrayShuffle;

And then

for(var i in arrays){
    arrays[i].shuffle()
}

same thing to position of arrays inside the toplevel array.

//EDIT: Missreading :)

function shuffleAnyNumber (arrays) {
   var numbers = new Array();     //collection of all numbers

   for(var i in this){
       for(var j in arrays[i]){
          numbers.push( arrays[i][j]);        //collect numbers out of the given arrays
       }       
   }

   numbers.shuffle(); //Method shown above

   var output = new Array();
   var tempArray= new Array();

   //putting it together
   for(var i in numbers){
       if(tempArray.length == 3){
            output.push(tempArray);
            tempArray = new Array();
       } else {
            tempArray.push(numbers[i]);
       }
   }

   return output;
}

i ' d say it will work like that.

Konstantin Krass
  • 8,626
  • 1
  • 18
  • 24
  • This looks like it only shuffles within each subarray, it won't shuffle between subarrays. – Barmar Feb 22 '13 at 21:11
  • Yeah I kinda missread. But this would work, by collect all numbers into 1 array, shuffle them and put them back into arrays by length of 3. – Konstantin Krass Feb 22 '13 at 21:13
1

You could flatten you array, shuffle it, and then split it up again:

var flat = [].concat.apply([], myArray);
arrayShuffle(flat);
var newArray = [],
    sublen = myArray[0].length;
for (var i=0; i<flat.length; i+= sublen)
    newArray.push(flat.slice(i, i+sublen));

Or you modify one of the exisiting shuffle algorithms to use items from your subarrays. For example, the Fisher-Yates-shuffle:

function shuffle2dArray(array) {
    if (!array.length) return array;
    var sublen = array[0].length,
        len = array.length * sublen;
    for (var i = len - 1; i > 0; i--) {
        var j = Math.floor(Math.random() * (i + 1));
        var ix = ~~(i/sublen),
            iy = i % sublen,
            jx = ~~(j/sublen),
            jy = j % sublen;
        var temp = array[ix][iy];
        array[ix][iy] = array[jx][jy];
        array[jx][jy] = temp;
    }
    return array;
}
Community
  • 1
  • 1
Bergi
  • 630,263
  • 148
  • 957
  • 1,375
1

This shuffles in place, it doesn't return a new array:

function shuffleMatrix (m) {
   if (m.length == 0 || m[0].length == 0) {
       // no rows or columns, just return it
       return m;
   }
   function swap(i1, j1, i2, j2) {
       if (i1 != i2 || j1 != j2) {
           var temp = m[i1][j1];
           m[i1][j1] = m[i2][j2];
           m[i2][j2] = temp;
   }
   var rows = m.length;
   var cols = m[0].length;
   for (i = 0; i < rows; i++) {
       for (j = 0; j < cols; j++) {
           var new_i = Math.random()*rows;
           var new_j = Math.random()*cols;
           swap(i, j, new_i, new_j);
       }
   }
}
Barmar
  • 741,623
  • 53
  • 500
  • 612
0

I 100% endorse Ilan Berci's answer. However, you could write it in a more functional style using underscore:

var v = [[1,2,3],[4,5,6],[7,8,9],[10,11,12],[13,14,15],[16,17,18]];

return _(v).chain().flatten().shuffle().groupBy(function(item, i) { 
    return i % v.length; 
}).values().value();

Go underscore!!

Travis Kaufman
  • 2,867
  • 22
  • 23