-
Notifications
You must be signed in to change notification settings - Fork 145
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
reduce the runtime of pick
, fixes #285
#286
Changes from 4 commits
60ce252
f529f43
bf7c349
c5c7e01
ac79f64
34c63ee
eefe423
0bcee5c
b7a233b
d304e53
2dca6ce
ed98365
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -1693,6 +1693,23 @@ Stream.prototype.pluck = function (prop) { | |
}; | ||
exposeMethod('pluck'); | ||
|
||
/** | ||
* Only applies the transformation strategy on Objects. | ||
* This helper is used in `pick` and `pickBy` | ||
**/ | ||
|
||
var objectOnly = _.curry(function(strategy, x) { | ||
if (_.isObject(x)) { | ||
return strategy(x); | ||
} | ||
else { | ||
throw new Error( | ||
'Expected Object, got ' + (typeof x) | ||
); | ||
} | ||
}); | ||
|
||
|
||
/** | ||
* | ||
* Retrieves copies of all the enumerable elements in the collection | ||
|
@@ -1723,32 +1740,23 @@ exposeMethod('pluck'); | |
*/ | ||
|
||
Stream.prototype.pickBy = function (f) { | ||
|
||
return this.consume(function (err, x, push, next) { | ||
return this.map(objectOnly(function (x) { | ||
var out = {}; | ||
if (err) { | ||
push(err); | ||
next(); | ||
} | ||
else if (x === nil) { | ||
push(err, x); | ||
} | ||
else if (_.isObject(x)) { | ||
for (var k in x) { | ||
if (f(k, x[k])) { | ||
out[k] = x[k]; | ||
} | ||
var props = []; // cache of already seen properties | ||
var obj = x; // variable used to transverse prototype chain | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Do you mean "traverse" here? |
||
|
||
// function created here so we don't create one per loop | ||
var testAndAdd = function (prop) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Function expression vs function statement again. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. In this case, it is an optimization b/c it creates the function once instead of once per loop iteration. I placed a comment above it to note why this code is inconsistent with the rest of the library. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm not sure what you mean. Couldn't you replace var testAndAdd = function (prop) {
...
} with function testAndAdd(prop) {
...
} Why would There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ahh, got it I thought you meant put the declaration inside the loop as an anonymous function. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. done |
||
if (props.indexOf(prop) === -1 && f(prop, x[prop])) { | ||
out[prop] = x[prop]; | ||
} | ||
push(null, out); | ||
next(); | ||
} | ||
else { | ||
push(new Error( | ||
'Expected Object, got ' + (typeof x) | ||
)); | ||
next(); | ||
} | ||
}); | ||
}; | ||
do { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We need to check if There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. this is handled by There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Oh, right. I didn't notice that. |
||
Object.getOwnPropertyNames(obj).forEach(testAndAdd); | ||
obj = Object.getPrototypeOf(obj); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Object.getPrototypeOf is not supported by IE8. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @brentpayne We have ES5 detection and the inherited keys function around the streamifyAll implementation. We should fallback to a There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. thanks will switch this over There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. done and noted in function doc string There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. added tests for ES3, but I don't have a headless ES3 browser for testing with testling. Any suggestions for testing this? |
||
} while (obj); | ||
return out; | ||
})); | ||
}; | ||
exposeMethod('pickBy'); | ||
|
||
|
@@ -1789,14 +1797,16 @@ exposeMethod('pickBy'); | |
* });*/ | ||
|
||
Stream.prototype.pick = function (properties) { | ||
return this.pickBy(function (key) { | ||
return this.map(objectOnly(function(x) { | ||
var out = {}; | ||
for (var i = 0, length = properties.length; i < length; i++) { | ||
if (properties[i] === key) { | ||
return true; | ||
var p = properties[i]; | ||
if (p in x) { | ||
out[p] = x[p]; | ||
} | ||
} | ||
return false; | ||
}); | ||
return out; | ||
})); | ||
}; | ||
exposeMethod('pick'); | ||
|
||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Doesn't look like anything is actually pushed to
props
. Also, instead of using an array andindexOf
(which I assume is a linear operation), should we use a regular object instead (setprops[prop] = true
, checkif (props[prop])
)? We definitely don't wantpickBy
to be anO(n^2)
operation.Also, can you add a check for this case?
Edit: http://jsperf.com/property-lookup-vs-indexof/2
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
great fix, was worried about this didn't think of this solution.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done