Skip to content

Loading…

Add _.indexBy #1008

Closed
wants to merge 2 commits into from

4 participants

@ansman

_.groupBy could be used for this as well but I feel like doing this:
grouped[attr][0] is kinda ugly.

I think it's quite often that you want to create a lookup table where
you map each object some unique attribute.

If the key iterator doesn't generate unique keys the last value for each
key is used.

@ansman ansman Add _.indexBy
`_.groupBy` could be used for this as well but I feel like doing this:
`grouped[attr][0]` is kinda ugly.

I think it's quite often that you want to create a lookup table where
you map each object some unique attribute.

If the key iterator doesn't generate unique keys the last value for each
key is used.
ae34217
@jdalton
Collaborator

I've seen this requested recently as _.toLookup.

@ansman

I don't really have a preference. Do you want me to switch?

@jdalton
Collaborator

@ansman Naw, just throwing it out there in case others recognize it by a diff name. No worries.

@bjmiller

If that's the case, one should probably alias the other.

@ansman

That makes sense :)

@jdalton jdalton referenced this pull request in lodash/lodash
Closed

Feature Request: _.toLookup #205

@jashkenas
Owner

Between groupBy and reduce, I think that this use case is fairly well covered. I don't think it's quite common enough that you'd need a new method, over groupBy, for it. Especially when it's not short-circuiting for efficiency.

@jashkenas jashkenas closed this
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Commits on Mar 8, 2013
  1. @ansman

    Add _.indexBy

    ansman committed
    `_.groupBy` could be used for this as well but I feel like doing this:
    `grouped[attr][0]` is kinda ugly.
    
    I think it's quite often that you want to create a lookup table where
    you map each object some unique attribute.
    
    If the key iterator doesn't generate unique keys the last value for each
    key is used.
  2. @ansman

    Alias _.indexBy to _.toLookup

    ansman committed
Showing with 58 additions and 0 deletions.
  1. +49 −0 test/collections.js
  2. +9 −0 underscore.js
View
49 test/collections.js
@@ -371,6 +371,55 @@ $(document).ready(function() {
deepEqual(_.groupBy(matrix, 1), {2: [[1,2]], 3: [[1,3], [2,3]]})
});
+ test('indexBy', function() {
+ var objectModels = [
+ {id: 'abc', name: 'Foo'},
+ {id: 'xyz', name: 'Bar'},
+ {id: 'mno', name: 'Baz'}
+ ];
+
+ var expectedObjectIndex = {
+ abc: {id: 'abc', name: 'Foo'},
+ xyz: {id: 'xyz', name: 'Bar'},
+ mno: {id: 'mno', name: 'Baz'}
+ };
+
+ var actualIndex = _.indexBy(objectModels, function(m) { return m.id });
+ deepEqual(actualIndex, expectedObjectIndex, 'can index by a function');
+
+ var actualIndex = _.indexBy(objectModels, 'id');
+ deepEqual(actualIndex, expectedObjectIndex, 'can index by a property');
+
+ var listModels = [
+ ['foo'],
+ ['bar'],
+ ['baz']
+ ];
+
+ var actualIndex = _.indexBy(listModels, 0);
+ deepEqual(actualIndex, {foo: ['foo'], bar: ['bar'], baz: ['baz']}, 'can index by array index');
+
+ var obj = {foo: 'bar'};
+ var objectIterator = function() {
+ var args = Array.prototype.slice.call(arguments, 0);
+ deepEqual(args.slice(0), ['bar', 'foo', obj], 'passes the value, key and object to the iterator when using objects');
+ };
+ _.indexBy(obj, objectIterator);
+
+ var list = ['foo'];
+ var listIterator = function() {
+ var args = Array.prototype.slice.call(arguments, 0);
+ deepEqual(args, ['foo', 0, list], 'passes the value, index and list to the iterator when using lists');
+ };
+ _.indexBy(list, listIterator);
+
+ var contextChecker = function() { equal(this, window, 'defaults the context to window') };
+ _.indexBy(list, listIterator);
+
+ contextChecker = function() { equal(this, obj, 'can accept a context') };
+ _.indexBy(list, listIterator, obj);
+ });
+
test('countBy', function() {
var parity = _.countBy([1, 2, 3, 4, 5], function(num){ return num % 2 == 0; });
equal(parity['true'], 2);
View
9 underscore.js
@@ -340,6 +340,15 @@
});
};
+ //
+ // Index the object's values by a criterion. Pass either a string attribute
+ // to index by, or a function that returns the criterion.
+ _.indexBy = _.toLookup = function(obj, value, context) {
+ return group(obj, value, context, function(result, key, value) {
+ result[key] = value;
+ });
+ };
+
// Counts instances of an object that group by a certain criterion. Pass
// either a string attribute to count by, or a function that returns the
// criterion.
Something went wrong with that request. Please try again.