4

I've got two arrays

var mp3 = ['sing.mp3','song.mp3','tune.mp3','jam.mp3',etc];
var ogg = ['sing.ogg','song.ogg','tune.ogg','jam.ogg',etc];

i need to shuffle both arrays so that they come out the same way, ex:

var mp3 = ['tune.mp3','song.mp3','jam.mp3','sing.mp3',etc];
var ogg = ['tune.ogg','song.ogg','jam.ogg','sing.ogg',etc];

there's a few posts on stackoverflow that shuffle arrays in different ways--this one is pretty great--but none of them demonstrate how to shuffle two arrays in the same exact way.

thnx!

3
  • 1
    if the filenames are the same for both the arrays, why can't you use one array instead of two? var files = ['tunes', 'jam', 'sing']; And, you can call tunes.mp3 or tunes.ogg depending on your application. Commented Aug 12, 2013 at 19:11
  • the arrays (which are fairly large) are dynamically generated from a directory of files, so they include the file extensions (.mp3 or .ogg) so there is no array that contains an extensionless list like ['tunes', 'jam', 'sing']... but are you suggesting that it might be easier to create a third array by somehow automatically stripping off the extensions? Commented Aug 12, 2013 at 19:15
  • 1
    In general, it would be easier to just shuffle one array and use the output rather than shuffling 2 arrays - specifically if you are expecting the same output and the arrays are fairly large. Commented Aug 12, 2013 at 19:18

5 Answers 5

8

Add an extra argument to the Fisher-Yates shuffle. (assumes that your arrays are equal length)

var mp3 = ["sing.mp3", "song.mp3"];
var ogg = ["sing.ogg", "song.ogg"];

function shuffle(obj1, obj2) {
  var index = obj1.length;
  var rnd, tmp1, tmp2;

  while (index) {
    rnd = Math.floor(Math.random() * index);
    index -= 1;
    tmp1 = obj1[index];
    tmp2 = obj2[index];
    obj1[index] = obj1[rnd];
    obj2[index] = obj2[rnd];
    obj1[rnd] = tmp1;
    obj2[rnd] = tmp2;
  }
}

shuffle(mp3, ogg);

console.log(mp3, ogg);

UPDATE:

If you are going to support more arrays (as suggested in the comments), then you could modify the Fisher-Yates as follows (aswell as perform some checks to make sure that the arguments are of Array and that their lengths match).

var isArray = Array.isArray || function(value) {
  return {}.toString.call(value) !== "[object Array]"
};

var mp3 = ["sing.mp3", "song.mp3", "tune.mp3", "jam.mp3"];
var ogg = ["sing.ogg", "song.ogg", "tune.ogg", "jam.ogg"];
var acc = ["sing.acc", "song.acc", "tune.acc", "jam.acc"];
var flc = ["sing.flc", "song.flc", "tune.flc", "jam.flc"];

function shuffle() {
  var arrLength = 0;
  var argsLength = arguments.length;
  var rnd, tmp;

  for (var index = 0; index < argsLength; index += 1) {
    if (!isArray(arguments[index])) {
      throw new TypeError("Argument is not an array.");
    }

    if (index === 0) {
      arrLength = arguments[0].length;
    }

    if (arrLength !== arguments[index].length) {
      throw new RangeError("Array lengths do not match.");
    }
  }

  while (arrLength) {
    rnd = Math.floor(Math.random() * arrLength);
    arrLength -= 1;
    for (argsIndex = 0; argsIndex < argsLength; argsIndex += 1) {
      tmp = arguments[argsIndex][arrLength];
      arguments[argsIndex][arrLength] = arguments[argsIndex][rnd];
      arguments[argsIndex][rnd] = tmp;
    }
  }
}

shuffle(mp3, ogg, acc, flc);

console.log(mp3, ogg, acc, flc);

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

5 Comments

@Nick it'll seem less perfect if you start supporting AAC and FLAC :)
true, but for reasons beyond my control this has to be mp3 && ogg only, so this is just the right quick fix :)
@Pointy, just noticed your answer, very elegant!!! wasn't there a moment ago when I accepted this one
careful! Should be Math.round. If you have two arrays of length 2, you dont get randomisation. I post on this below.
Math.round was not the problem, it was a bad Fisher-Yates implementation. :)
1

From that example, simply add a second parameter (your second array) and perform the operation on both arrays. You will just need to add and use a second temp, so you aren't overwriting your temps.

This should do the trick ASSUMING THE ARRAYS ARE THE SAME LENGTH:

function shuffle(array, array2) {
    var counter = array.length, temp, temp2, index;

    // While there are elements in the array
    while (counter > 0) {
        // Pick a random index
        index = Math.floor(Math.random() * counter);

        // Decrease counter by 1
        counter--;

        // And swap the last element with it
        temp = array[counter];
        temp2 = array2[counter];

        array[counter] = array[index];
        array2[counter] = array2[index];

        array[index] = temp;
        array2[index] = temp2;
    }
}

1 Comment

Note: After passing mp3 and ogg to the function, those variables will be themselves shuffled, no need for the return and further assignments.
1

I would seriously consider restructuring the way you're keeping track of the information, but in general you can separate out the shuffle itself from the stuff being shuffled. You need a function to generate a random permutation, and then a function to apply a permutation to an array.

function shuffle(o) { //v1.0
    for(var j, x, i = o.length; i; j = Math.floor(Math.random() * i), x = o[--i], o[i] = o[j], o[j] = x);
    return o;
};

function permutation( length ) {
  var p = [], i;
  for (i = 0; i < length; ++i) p[i] = i;
  return shuffle(p);
}

function permute( a, p ) {
  var r = [];
  for (var i = 0; i < a.length; ++i)
    r.push(a[p[i]]);
  for (i = 0; i < a.length; ++i)
    a[i] = r[i];
}

Then you can create a single random permutation and apply it to any list (of the right length) you want.

var p = permutation( mp3.length );
permute(mp3, p);
permute(ogg, p);
permute(aac, p);
// etc

(Shuffle function taken from the SO question linked in the OP.)

Comments

0

If you have two arrays of length 2, @Xotic750s function always returns the same value. UseMath.round instead of Math.floor.

function shuffle_two_arrays_identically(arr1, arr2){
"use strict";
var l = arr1.length,
    i = 0,
    rnd,
    tmp1,
    tmp2;

while (i < l) {
    rnd = Math.round(Math.random() * i)
    tmp1 = arr1[i]
    tmp2 = arr2[i]
    arr1[i] = arr1[rnd]
    arr2[i] = arr2[rnd]
    arr1[rnd] = tmp1
    arr2[rnd] = tmp2
    i += 1
}}

Comments

0

<script>
var arrayList= ['a','b','c','d','e','f','g'];
arrayList.sort(function(){
    return 0.5 - Math.random()
})

document.getElementById("output").innerHTML  = arrayList;

<script>

2 Comments

While this code may answer the question, providing additional context regarding why and/or how this code answers the question improves its long-term value.
Noted and Thanks

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.