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.

6
  • What is your logic here ? Commented Feb 22, 2013 at 21:07
  • Just a random shuffle? Commented Feb 22, 2013 at 21:08
  • Is this just a random rearrangement, but keeping the same dimensions? Commented Feb 22, 2013 at 21:08
  • Can we assume that all the subarrays are the same length? Commented Feb 22, 2013 at 21:09
  • @Barmar - Yes, all subarrays are the same length and need to keep the subarrays in the new array the same length as old one too Commented Feb 22, 2013 at 21:11

5 Answers 5

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;
})

Sign up to request clarification or add additional context in comments.

Comments

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);
       }
   }
}

Comments

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.

2 Comments

This looks like it only shuffles within each subarray, it won't shuffle between subarrays.
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.
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;
}

1 Comment

I like the first solution since I am already flattening that array in my code.
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!!

1 Comment

I fully endorse your functional rewrite! :)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.