4

I want to get a randomly sorted set from a Meteor collection. What is the best/most efficient way?

Mongo options are controversial.

I am currently using underscore _.shuffle which is quite neat, eg:

Template.userList.helpers({
  users: function() {
    return _.shuffle(Meteor.users.find().fetch());
  }
});

I use Jade, so maybe there's an option at the templating level?

KindOfGuy
  • 3,081
  • 5
  • 31
  • 47
  • Question: Since you're using an array in your template rather than a cursor, is it still reactive? – Kyll Nov 21 '14 at 14:10
  • @Kyll, yes, but the entire helper will be recalculated if updates to the collection is made, so no nice fine-grained updates, which may or may not be a problem. – Peppe L-G Nov 21 '14 at 15:08
  • this is the best solution I have found, I think there is not a better way of achieve the same. – svelandiag Jul 22 '15 at 21:15

1 Answers1

0

You could use Lodash _.shuffle, like so:

Template.userList.helpers({
  users: function() {
    return _.shuffle(Meteor.users.find().fetch());
  }
});

As hilarious as that might seem, there is a difference under the hood:

Underscore (source)

_.shuffle = function(obj) {
  var set = isArrayLike(obj) ? obj : _.values(obj);
  var length = set.length;
  var shuffled = Array(length);
  for (var index = 0, rand; index < length; index++) {
    rand = _.random(0, index);
    if (rand !== index) shuffled[index] = shuffled[rand];
    shuffled[rand] = set[index];
  }
  return shuffled;
};

Lo-Dash (slightly modified for ease of comparison, source)

_.shuffle = function(collection) {
  MAX_ARRAY_LENGTH = 4294967295;
  return sampleSize(collection, MAX_ARRAY_LENGTH);
}

function sampleSize(collection, n) {
  var index = -1,
      result = toArray(collection),
      length = result.length,
      lastIndex = length - 1;

  n = clamp(toInteger(n), 0, length);
  while (++index < n) {
    var rand = baseRandom(index, lastIndex),
        value = result[rand];

    result[rand] = result[index];
    result[index] = value;
  }
  result.length = n;
  return result;
}

You can take a look at this SO discussion for a more in-depth look at comparing the two libraries.

Both, Underscore and Lo-Dash, use the Fisher-Yates shuffle which you'd have a hard time doing "better" than.

Community
  • 1
  • 1
Jesse
  • 2,043
  • 9
  • 28
  • 45