Creates an array of elements, sorted in ascending order by the results of
running each element in a collection through the callback. This method
performs a stable sort, that is, it will preserve the original sort order
of equal elements. The callback is bound to `thisArg` and invoked with
three arguments; (value, index|key, collection).

If a property name is provided for `callback` the created "_.pluck" style
callback will return the property value of the given element.

If an object is provided for `callback` the created "_.where" style callback
will return `true` for elements that have the properties of the given object,
else `false`.

@static
@memberOf _
@category Collections
@param {Array|Object|string} collection The collection to iterate over.
@param {Function|Object|string} [callback=identity] The function called
per iteration. If a property name or object is provided it will be used
to create a "_.pluck" or "_.where" style callback, respectively.
@param {*} [thisArg] The `this` binding of `callback`.
@returns {Array} Returns a new array of sorted elements.
@example

_.sortBy([1, 2, 3], function(num) { return Math.sin(num); });
// => [3, 1, 2]

_.sortBy([1, 2, 3], function(num) { return this.sin(num); }, Math);
// => [3, 1, 2]

// using "_.pluck" callback shorthand
_.sortBy(['banana', 'strawberry', 'apple'], 'length');
// => ['apple', 'banana', 'strawberry']
function sortBy(collection, callback, thisArg) {
      var index = -1,
          length = collection ? collection.length : 0,
          result = Array(typeof length == 'number' ? length : 0);

      callback = lodash.createCallback(callback, thisArg, 3);
      forEach(collection, function(value, key, collection) {
        var object = result[++index] = getObject();
        object.criteria = callback(value, key, collection);
        object.index = index;
        object.value = value;
      });

      length = result.length;
      result.sort(compareAscending);
      while (length--) {
        var object = result[length];
        result[length] = object.value;
        releaseObject(object);
      }
      return result;
    }