jashkenas/underscore — pull request #1420 by antivanov (2014-01-26 23:01:04+00:00)
Title: Re-factored _.object to use _.zip and _.reduce, added tests

I noticed that at least for my taste the current implementation of ```_.object``` can be made more high level, clearer and shorter if we use ```_.reduce``` and ```_.zip```:

The current version:

```javascript
_.object = function(list, values) {
if (list == null) return {};
var result = {};
for (var i = 0, length = list.length; i < length; i++) {
if (values) {
result[list[i]] = values[i];
} else {
result[list[i][0]] = list[i][1];
}
}
return result;
};
```

Alternative implementation using ```._reduce``` and ```._zip``` that I found:

```javascript
_.object = function(list, values) {
if (list == null) return {};
var pairs = values ? _.zip(list, _.take(values, list.length)) : list;
return _.reduce(pairs, function(result, pair) {
result[pair[0]] = pair[1];
return result;
}, {});
};
```

If we omit ```_.take(values, list.length)``` and just use ```values``` then the code will be even clearer but the backward compatibility will be broken according to the first test case I added (see below).

What do you think, should we substitute the current implementation of ```_.object``` with the alternative one?

I can create a fork, commit my changes and then create a pull request, but before that I wanted to discuss the change. Or alternatively the changes can be applied as described in this issue.

#### Testing

I checked that the unit tests pass and added a few new ones to ensure backward compatibility for corner cases.

```javascript
test('object', function() {
...

ok(_.isEqual(_.object(["a", "b", "c"], [1, 2, 3, 4, 5]), {"a": 1, "b": 2, "c": 3}), 'extra values are ignored');
ok(_.isEqual(_.object([void 0, "b", "c"], [1, 2, 3]), {undefined: 1, "b": 2, "c": 3}), '"void 0" is handled in keys');
ok(_.isEqual(_.object([void 0, "b", void 0], [1, 2, 3]), {"b": 2, undefined: 3}), 'several "void 0" are handled in keys');
});
```

#### Performance concerns

One thing that can be worse in the alternative version compared to the current one is using more memory by creating an extra object ```pairs``` and having extra calls to higher level functions ```_.take```, ```_.zip``` and ```_.reduce```. But on the other hand it is a bit more expressive.