From d8194c0886a8ca08b279475f60cb9b8d8e8afd90 Mon Sep 17 00:00:00 2001 From: John-David Dalton Date: Fri, 22 Nov 2013 09:16:18 -0800 Subject: [PATCH] Allow `_.sortBy` to accept an array for `callback`. --- dist/lodash.compat.js | 69 ++++++++++++++++++++-------- dist/lodash.compat.min.js | 84 +++++++++++++++++------------------ dist/lodash.js | 69 ++++++++++++++++++++-------- dist/lodash.min.js | 16 +++---- dist/lodash.underscore.js | 57 ++++++++++++++++-------- dist/lodash.underscore.min.js | 6 +-- lodash.js | 67 ++++++++++++++++++++-------- test/saucelabs.js | 4 +- test/test.js | 12 +++++ 9 files changed, 255 insertions(+), 129 deletions(-) diff --git a/dist/lodash.compat.js b/dist/lodash.compat.js index 5bd7e874a..3ee9a1697 100644 --- a/dist/lodash.compat.js +++ b/dist/lodash.compat.js @@ -281,22 +281,29 @@ */ function compareAscending(a, b) { var ac = a.criteria, - bc = b.criteria; + bc = b.criteria, + index = -1, + length = ac.length; - // ensure a stable sort in V8 and other engines - // http://code.google.com/p/v8/issues/detail?id=90 - if (ac !== bc) { - if (ac > bc || typeof ac == 'undefined') { - return 1; - } - if (ac < bc || typeof bc == 'undefined') { - return -1; + while (++index < length) { + var value = ac[index], + other = bc[index]; + + if (value !== other) { + if (value > other || typeof value == 'undefined') { + return 1; + } + if (value < other || typeof other == 'undefined') { + return -1; + } } } - // The JS engine embedded in Adobe applications like InDesign has a buggy - // `Array#sort` implementation that causes it, under certain circumstances, - // to return the same value for `a` and `b`. - // See https://github.com/jashkenas/underscore/pull/1247 + // Fixes an `Array#sort` bug in the JS engine embedded in Adobe applications + // that causes it, under certain circumstances, to return the same value for + // `a` and `b`. See https://github.com/jashkenas/underscore/pull/1247 + // + // This also ensures a stable sort in V8 and other engines. + // See http://code.google.com/p/v8/issues/detail?id=90 return a.index - b.index; } @@ -4301,6 +4308,9 @@ * If a property name is provided for `callback` the created "_.pluck" style * callback will return the property value of the given element. * + * If an array of property names is provided for `callback` the collection + * will be sorted by each property value. + * * 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`. @@ -4309,7 +4319,7 @@ * @memberOf _ * @category Collections * @param {Array|Object|string} collection The collection to iterate over. - * @param {Function|Object|string} [callback=identity] The function called + * @param {Array|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`. @@ -4322,19 +4332,37 @@ * _.sortBy([1, 2, 3], function(num) { return this.sin(num); }, Math); * // => [3, 1, 2] * + * var characters = [ + * { 'name': 'barney', 'age': 36 }, + * { 'name': 'fred', 'age': 40 }, + * { 'name': 'barney', 'age': 26 }, + * { 'name': 'fred', 'age': 30 } + * ]; + * * // using "_.pluck" callback shorthand - * _.sortBy(['banana', 'strawberry', 'apple'], 'length'); - * // => ['apple', 'banana', 'strawberry'] + * _.map(_.sortBy(characters, 'age'), _.values); + * // => [['barney', 26], ['fred', 30], ['barney', 36], ['fred', 40]] + * + * // sorting by multiple properties + * _.map(_.sortBy(characters, ['name', 'age']), _.values); + * // = > [['barney', 26], ['barney', 36], ['fred', 30], ['fred', 40]] */ function sortBy(collection, callback, thisArg) { var index = -1, + isArr = isArray(callback), length = collection ? collection.length : 0, result = Array(typeof length == 'number' ? length : 0); - callback = lodash.createCallback(callback, thisArg, 3); + if (!isArr) { + callback = lodash.createCallback(callback, thisArg, 3); + } forEach(collection, function(value, key, collection) { var object = result[++index] = getObject(); - object.criteria = callback(value, key, collection); + if (isArr) { + object.criteria = map(callback, function(key) { return value[key]; }); + } else { + (object.criteria = getArray())[0] = callback(value, key, collection); + } object.index = index; object.value = value; }); @@ -4344,6 +4372,9 @@ while (length--) { var object = result[length]; result[length] = object.value; + if (!isArr) { + releaseArray(object.criteria); + } releaseObject(object); } return result; @@ -6196,7 +6227,7 @@ * _.capitalize('fred'); * // => 'Fred' * - * _('fred').capitalize(); + * _('fred').capitalize().value(); * // => 'Fred' */ function mixin(object, source) { diff --git a/dist/lodash.compat.min.js b/dist/lodash.compat.min.js index 03576cdc2..3eff6feef 100644 --- a/dist/lodash.compat.min.js +++ b/dist/lodash.compat.min.js @@ -4,57 +4,57 @@ * Build: `lodash -o ./dist/lodash.compat.js` */ ;(function(){function n(n,t,e){e=(e||0)-1;for(var r=n?n.length:0;++er||typeof e=="undefined")return 1;if(ee?0:e);++r=_&&a===n,f=[];if(l){var c=o(r);c?(a=t,r=c):l=false}for(;++ua(r,c)&&f.push(c);return l&&p(r),f}function it(n,t,e,r){r=(r||0)-1;for(var u=n?n.length:0,o=[];++r=_&&l===n,h=u||g?i():s;if(g){var v=o(h);v?(l=t,h=v):(g=false,h=u?h:(c(h),s))}for(;++al(h,y))&&((u||g)&&h.push(y),s.push(v))}return g?(c(h.k),p(h)):u&&c(h),s}function st(n){return function(t,e,r){var u={};if(e=v.createCallback(e,r,3),We(t)){r=-1;for(var o=t.length;++rk;k++)r+="n='"+e.h[k]+"';if((!(r&&x[n])&&m.call(t,n))",e.j||(r+="||(!x[n]&&t[n]!==A[n])"),r+="){"+e.g+"}";r+="}"}return(e.b||qe.nonEnumArgs)&&(r+="}"),r+=e.c+";return E",n("d,j,k,m,o,p,q,s,v,A,B,y,I,J,L",t+r+"}")(tt,q,se,xe,d,bt,We,Et,Q.f,ge,X,ze,M,he,ye) -}function vt(n){return Ue[n]}function yt(){var t=(t=v.indexOf)===qt?n:t;return t}function mt(n){var t,e;return!n||ye.call(n)!=G||(t=n.constructor,xt(t)&&!(t instanceof t))||!qe.argsClass&&bt(n)||!qe.nodeClass&&f(n)?false:qe.ownLast?(er(n,function(n,t,r){return e=xe.call(r,t),false}),false!==e):(er(n,function(n,t){e=t}),typeof e=="undefined"||xe.call(n,e))}function dt(n){return Qe[n]}function bt(n){return n&&typeof n=="object"&&typeof n.length=="number"&&ye.call(n)==$||false}function _t(n,t,e){var r=Je(n),u=r.length; -for(t=tt(t,e,3);u--&&(e=r[u],false!==t(n[e],e,n)););return n}function wt(n){var t=[];return er(n,function(n,e){xt(n)&&t.push(e)}),t.sort()}function jt(n){for(var t=-1,e=Je(n),r=e.length,u={};++te?Re(0,o+e):e)||0,We(n)?a=-1o&&(o=i)}}else t=null==t&&Et(n)?r:v.createCallback(t,e,3),Ze(n,function(n,e,r){e=t(n,e,r),e>u&&(u=e,o=n) -});return o}function Ft(n,t,e,r){var u=3>arguments.length;if(t=v.createCallback(t,r,4),We(n)){var o=-1,a=n.length;for(u&&(e=n[++o]);++oarguments.length;return t=v.createCallback(t,r,4),Bt(n,function(n,r,o){e=u?(u=false,n):t(e,n,r,o)}),e}function Tt(n){var t=-1,e=n?n.length:0,r=te(typeof e=="number"?e:0);return Nt(n,function(n){var e=ct(0,++t);r[t]=r[e],r[e]=n}),r}function Lt(n,t,e){var r;if(t=v.createCallback(t,e,3),We(n)){e=-1; -for(var u=n.length;++er?Re(0,u+r):r||0}else if(r)return r=Wt(t,e),t[r]===e?r:-1;return n(t,e,r)}function Kt(n,t,e){if(typeof t!="number"&&null!=t){var r=0,u=-1,o=n?n.length:0; -for(t=v.createCallback(t,e,3);++u>>1,e(n[r])e?0:e);++t=h;m?(a&&(a=be(a)),s=l,i=n.apply(f,o)):a||(a=Ee(r,h))}return m&&c?c=be(c):c||t===g||(c=Ee(u,t)),e&&(m=true,i=n.apply(f,o)),!m||c||a||(o=f=null),i}}function Ut(n){if(!xt(n))throw new ce;var t=s(arguments,1);return Ee(function(){n.apply(h,t)},1)}function Qt(n){return n -}function Xt(n,t){var e=n,r=!t||xt(e);t||(e=y,t=n,n=v),Nt(wt(t),function(u){var o=n[u]=t[u];r&&(e.prototype[u]=function(){var t=this.__wrapped__,r=[t];return Ce.apply(r,arguments),r=o.apply(n,r),t&&typeof t=="object"&&t===r?this:(r=new e(r),r.__chain__=this.__chain__,r)})})}function Yt(){}function Zt(n){return function(t){return t[n]}}function ne(){return this.__wrapped__}e=e?ut.defaults(Z.Object(),e,ut.pick(Z,R)):Z;var te=e.Array,ee=e.Boolean,re=e.Date,ue=e.Function,oe=e.Math,ae=e.Number,ie=e.Object,le=e.RegExp,fe=e.String,ce=e.TypeError,pe=[],se=e.Error.prototype,ge=ie.prototype,he=fe.prototype,ve=e._,ye=ge.toString,me=le("^"+fe(ye).replace(/[.*+?^${}()|[\]\\]/g,"\\$&").replace(/toString| for [^\]]+/g,".*?")+"$"),de=oe.ceil,be=e.clearTimeout,_e=oe.floor,we=ue.prototype.toString,je=me.test(je=ie.getPrototypeOf)&&je,xe=ge.hasOwnProperty,Ce=pe.push,ke=ge.propertyIsEnumerable,Ee=e.setTimeout,Oe=pe.splice,Se=typeof(Se=rt&&et&&rt.setImmediate)=="function"&&!me.test(Se)&&Se,Ie=function(){try{var n={},t=me.test(t=ie.defineProperty)&&t,e=t(n,n,n)&&t -}catch(r){}return e}(),Ae=me.test(Ae=ie.create)&&Ae,De=me.test(De=te.isArray)&&De,Ne=e.isFinite,Be=e.isNaN,Pe=me.test(Pe=ie.keys)&&Pe,Re=oe.max,Fe=oe.min,$e=e.parseInt,Te=oe.random,Le={};Le[T]=te,Le[L]=ee,Le[z]=re,Le[K]=ue,Le[G]=ie,Le[W]=ae,Le[J]=le,Le[M]=fe;var ze={};ze[T]=ze[z]=ze[W]={constructor:true,toLocaleString:true,toString:true,valueOf:true},ze[L]=ze[M]={constructor:true,toString:true,valueOf:true},ze[q]=ze[K]=ze[J]={constructor:true,toString:true},ze[G]={constructor:true},function(){for(var n=F.length;n--;){var t,e=F[n]; -for(t in ze)xe.call(ze,t)&&!xe.call(ze[t],e)&&(ze[t][e]=false)}}(),y.prototype=v.prototype;var qe=v.support={};!function(){function n(){this.x=1}var t={0:1,length:1},r=[];n.prototype={valueOf:1,y:1};for(var u in new n)r.push(u);for(u in arguments);qe.argsClass=ye.call(arguments)==$,qe.argsObject=arguments.constructor==ie&&!(arguments instanceof te),qe.enumErrorProps=ke.call(se,"message")||ke.call(se,"name"),qe.enumPrototypes=ke.call(n,"prototype"),qe.funcDecomp=!me.test(e.p)&&B.test(g),qe.funcNames=typeof ue.name=="string",qe.nonEnumArgs=0!=u,qe.nonEnumShadows=!/valueOf/.test(r),qe.ownLast="x"!=r[0],qe.spliceObjects=(pe.splice.call(t,0,1),!t[0]),qe.unindexedChars="xx"!="x"[0]+ie("x")[0]; +}}function r(n){return n.charCodeAt(0)}function u(n,t){for(var e=n.m,r=t.m,u=-1,o=e.length;++ui||typeof a=="undefined")return 1;if(ae?0:e);++r=_&&a===n,f=[];if(l){var c=o(r);c?(a=t,r=c):l=false +}for(;++ua(r,c)&&f.push(c);return l&&p(r),f}function it(n,t,e,r){r=(r||0)-1;for(var u=n?n.length:0,o=[];++r=_&&l===n,h=u||g?i():s;if(g){var v=o(h);v?(l=t,h=v):(g=false,h=u?h:(c(h),s))}for(;++al(h,y))&&((u||g)&&h.push(y),s.push(v))}return g?(c(h.k),p(h)):u&&c(h),s}function st(n){return function(t,e,r){var u={};if(e=v.createCallback(e,r,3),We(t)){r=-1;for(var o=t.length;++rk;k++)r+="n='"+e.h[k]+"';if((!(r&&x[n])&&m.call(t,n))",e.j||(r+="||(!x[n]&&t[n]!==A[n])"),r+="){"+e.g+"}"; +r+="}"}return(e.b||qe.nonEnumArgs)&&(r+="}"),r+=e.c+";return E",n("d,j,k,m,o,p,q,s,v,A,B,y,I,J,L",t+r+"}")(tt,q,se,xe,d,bt,We,Et,Q.f,ge,X,ze,M,he,ye)}function vt(n){return Ue[n]}function yt(){var t=(t=v.indexOf)===qt?n:t;return t}function mt(n){var t,e;return!n||ye.call(n)!=G||(t=n.constructor,xt(t)&&!(t instanceof t))||!qe.argsClass&&bt(n)||!qe.nodeClass&&f(n)?false:qe.ownLast?(er(n,function(n,t,r){return e=xe.call(r,t),false}),false!==e):(er(n,function(n,t){e=t}),typeof e=="undefined"||xe.call(n,e))}function dt(n){return Qe[n] +}function bt(n){return n&&typeof n=="object"&&typeof n.length=="number"&&ye.call(n)==T||false}function _t(n,t,e){var r=Je(n),u=r.length;for(t=tt(t,e,3);u--&&(e=r[u],false!==t(n[e],e,n)););return n}function wt(n){var t=[];return er(n,function(n,e){xt(n)&&t.push(e)}),t.sort()}function jt(n){for(var t=-1,e=Je(n),r=e.length,u={};++te?Re(0,o+e):e)||0,We(n)?a=-1o&&(o=i)}}else t=null==t&&Et(n)?r:v.createCallback(t,e,3),Ze(n,function(n,e,r){e=t(n,e,r),e>u&&(u=e,o=n)});return o}function Ft(n,t,e,r){var u=3>arguments.length;if(t=v.createCallback(t,r,4),We(n)){var o=-1,a=n.length;for(u&&(e=n[++o]);++oarguments.length;return t=v.createCallback(t,r,4),Bt(n,function(n,r,o){e=u?(u=false,n):t(e,n,r,o) +}),e}function $t(n){var t=-1,e=n?n.length:0,r=te(typeof e=="number"?e:0);return Nt(n,function(n){var e=ct(0,++t);r[t]=r[e],r[e]=n}),r}function Lt(n,t,e){var r;if(t=v.createCallback(t,e,3),We(n)){e=-1;for(var u=n.length;++er?Re(0,u+r):r||0}else if(r)return r=Wt(t,e),t[r]===e?r:-1;return n(t,e,r)}function Kt(n,t,e){if(typeof t!="number"&&null!=t){var r=0,u=-1,o=n?n.length:0;for(t=v.createCallback(t,e,3);++u>>1,e(n[r])e?0:e);++t=h;m?(u&&(u=be(u)),c=a,o=n.apply(i,r)):u||(u=Ee(y,h))}return m&&l?l=be(l):l||t===p||(l=Ee(v,t)),e&&(m=true,o=n.apply(i,r)),!m||l||u||(r=i=null),o}}function Ut(n){if(!xt(n))throw new ce;var t=s(arguments,1); +return Ee(function(){n.apply(h,t)},1)}function Qt(n){return n}function Xt(n,t){var e=n,r=!t||xt(e);t||(e=y,t=n,n=v),Nt(wt(t),function(u){var o=n[u]=t[u];r&&(e.prototype[u]=function(){var t=this.__wrapped__,r=[t];return Ce.apply(r,arguments),r=o.apply(n,r),t&&typeof t=="object"&&t===r?this:(r=new e(r),r.__chain__=this.__chain__,r)})})}function Yt(){}function Zt(n){return function(t){return t[n]}}function ne(){return this.__wrapped__}e=e?ut.defaults(Z.Object(),e,ut.pick(Z,R)):Z;var te=e.Array,ee=e.Boolean,re=e.Date,ue=e.Function,oe=e.Math,ae=e.Number,ie=e.Object,le=e.RegExp,fe=e.String,ce=e.TypeError,pe=[],se=e.Error.prototype,ge=ie.prototype,he=fe.prototype,ve=e._,ye=ge.toString,me=le("^"+fe(ye).replace(/[.*+?^${}()|[\]\\]/g,"\\$&").replace(/toString| for [^\]]+/g,".*?")+"$"),de=oe.ceil,be=e.clearTimeout,_e=oe.floor,we=ue.prototype.toString,je=me.test(je=ie.getPrototypeOf)&&je,xe=ge.hasOwnProperty,Ce=pe.push,ke=ge.propertyIsEnumerable,Ee=e.setTimeout,Oe=pe.splice,Se=typeof(Se=rt&&et&&rt.setImmediate)=="function"&&!me.test(Se)&&Se,Ie=function(){try{var n={},t=me.test(t=ie.defineProperty)&&t,e=t(n,n,n)&&t +}catch(r){}return e}(),Ae=me.test(Ae=ie.create)&&Ae,De=me.test(De=te.isArray)&&De,Ne=e.isFinite,Be=e.isNaN,Pe=me.test(Pe=ie.keys)&&Pe,Re=oe.max,Fe=oe.min,Te=e.parseInt,$e=oe.random,Le={};Le[$]=te,Le[L]=ee,Le[z]=re,Le[K]=ue,Le[G]=ie,Le[W]=ae,Le[J]=le,Le[M]=fe;var ze={};ze[$]=ze[z]=ze[W]={constructor:true,toLocaleString:true,toString:true,valueOf:true},ze[L]=ze[M]={constructor:true,toString:true,valueOf:true},ze[q]=ze[K]=ze[J]={constructor:true,toString:true},ze[G]={constructor:true},function(){for(var n=F.length;n--;){var t,e=F[n]; +for(t in ze)xe.call(ze,t)&&!xe.call(ze[t],e)&&(ze[t][e]=false)}}(),y.prototype=v.prototype;var qe=v.support={};!function(){var n=function(){this.x=1},t={0:1,length:1},r=[];n.prototype={valueOf:1,y:1};for(var u in new n)r.push(u);for(u in arguments);qe.argsClass=ye.call(arguments)==T,qe.argsObject=arguments.constructor==ie&&!(arguments instanceof te),qe.enumErrorProps=ke.call(se,"message")||ke.call(se,"name"),qe.enumPrototypes=ke.call(n,"prototype"),qe.funcDecomp=!me.test(e.WinRTError)&&B.test(g),qe.funcNames=typeof ue.name=="string",qe.nonEnumArgs=0!=u,qe.nonEnumShadows=!/valueOf/.test(r),qe.ownLast="x"!=r[0],qe.spliceObjects=(pe.splice.call(t,0,1),!t[0]),qe.unindexedChars="xx"!="x"[0]+ie("x")[0]; try{qe.nodeClass=!(ye.call(document)==G&&!({toString:0}+""))}catch(o){qe.nodeClass=true}}(1),v.templateSettings={escape:/<%-([\s\S]+?)%>/g,evaluate:/<%([\s\S]+?)%>/g,interpolate:A,variable:"",imports:{_:v}},Ae||(nt=function(){function n(){}return function(t){if(Ct(t)){n.prototype=t;var r=new n;n.prototype=null}return r||e.Object()}}());var Ke=Ie?function(n,t){U.value=t,Ie(n,"__bindData__",U)}:Yt;qe.argsClass||(bt=function(n){return n&&typeof n=="object"&&typeof n.length=="number"&&xe.call(n,"callee")&&!ke.call(n,"callee")||false -});var We=De||function(n){return n&&typeof n=="object"&&typeof n.length=="number"&&ye.call(n)==T||false},Ge=ht({a:"z",e:"[]",i:"if(!(B[typeof z]))return E",g:"E.push(n)"}),Je=Pe?function(n){return Ct(n)?qe.enumPrototypes&&typeof n=="function"||qe.nonEnumArgs&&n.length&&bt(n)?Ge(n):Pe(n):[]}:Ge,Me={a:"g,e,K",i:"e=e&&typeof K=='undefined'?e:d(e,K,3)",b:"typeof u=='number'",v:Je,g:"if(e(t[n],n,g)===false)return E"},Ve={a:"z,H,l",i:"var a=arguments,b=0,c=typeof l=='number'?2:a.length;while(++b":">",'"':""","'":"'"},Qe=jt(Ue),Xe=le("("+Je(Qe).join("|")+")","g"),Ye=le("["+Je(Ue).join("")+"]","g"),Ze=ht(Me),nr=ht(Ve,{i:Ve.i.replace(";",";if(c>3&&typeof a[c-2]=='function'){var e=d(a[--c-1],a[c--],2)}else if(c>2&&typeof a[c-1]=='function'){e=a[--c]}"),g:"E[n]=e?e(E[n],t[n]):t[n]"}),tr=ht(Ve),er=ht(Me,He,{j:false}),rr=ht(Me,He); +});var We=De||function(n){return n&&typeof n=="object"&&typeof n.length=="number"&&ye.call(n)==$||false},Ge=ht({a:"z",e:"[]",i:"if(!(B[typeof z]))return E",g:"E.push(n)"}),Je=Pe?function(n){return Ct(n)?qe.enumPrototypes&&typeof n=="function"||qe.nonEnumArgs&&n.length&&bt(n)?Ge(n):Pe(n):[]}:Ge,Me={a:"g,e,K",i:"e=e&&typeof K=='undefined'?e:d(e,K,3)",b:"typeof u=='number'",v:Je,g:"if(e(t[n],n,g)===false)return E"},Ve={a:"z,H,l",i:"var a=arguments,b=0,c=typeof l=='number'?2:a.length;while(++b":">",'"':""","'":"'"},Qe=jt(Ue),Xe=le("("+Je(Qe).join("|")+")","g"),Ye=le("["+Je(Ue).join("")+"]","g"),Ze=ht(Me),nr=ht(Ve,{i:Ve.i.replace(";",";if(c>3&&typeof a[c-2]=='function'){var e=d(a[--c-1],a[c--],2)}else if(c>2&&typeof a[c-1]=='function'){e=a[--c]}"),g:"E[n]=e?e(E[n],t[n]):t[n]"}),tr=ht(Ve),er=ht(Me,He,{j:false}),rr=ht(Me,He); xt(/x/)&&(xt=function(n){return typeof n=="function"&&ye.call(n)==K});var ur=je?function(n){if(!n||ye.call(n)!=G||!qe.argsClass&&bt(n))return false;var t=n.valueOf,e=typeof t=="function"&&(e=je(t))&&je(e);return e?n==e||je(n)==e:mt(n)}:mt,or=st(function(n,t,e){xe.call(n,e)?n[e]++:n[e]=1}),ar=st(function(n,t,e){(xe.call(n,e)?n[e]:n[e]=[]).push(t)}),ir=st(function(n,t,e){n[e]=t}),lr=Pt;Se&&(Ut=function(n){if(!xt(n))throw new ce;return Se.apply(e,arguments)});var fr=me.test(fr=re.now)&&fr||function(){return(new re).getTime() -},cr=8==$e(j+"08")?$e:function(n,t){return $e(Et(n)?n.replace(D,""):n,t||0)};return v.after=function(n,t){if(!xt(t))throw new ce;return function(){return 1>--n?t.apply(this,arguments):void 0}},v.assign=nr,v.at=function(n){var t=arguments,e=-1,r=it(t,true,false,1),t=t[2]&&t[2][t[1]]===n?1:r.length,u=te(t);for(qe.unindexedChars&&Et(n)&&(n=n.split(""));++e--n?t.apply(this,arguments):void 0}},v.assign=nr,v.at=function(n){var t=arguments,e=-1,r=it(t,true,false,1),t=t[2]&&t[2][t[1]]===n?1:r.length,u=te(t);for(qe.unindexedChars&&Et(n)&&(n=n.split(""));++e=_&&o(r?e[r]:s)))}var f=e[0],h=-1,v=f?f.length:0,y=[];n:for(;++h(m?t(m,g):l(s,g))){for(r=u,(m||s).push(g);--r;)if(m=a[r],0>(m?t(m,g):l(e[r],g)))continue n;y.push(g) -}}for(;u--;)(m=a[u])&&p(m);return c(a),c(s),y},v.invert=jt,v.invoke=function(n,t){var e=s(arguments,2),r=-1,u=typeof t=="function",o=n?n.length:0,a=te(typeof o=="number"?o:0);return Nt(n,function(n){a[++r]=(u?t:n[t]).apply(n,e)}),a},v.keys=Je,v.map=Pt,v.mapValues=function(n,t,e){var r={};return t=v.createCallback(t,e,3),rr(n,function(n,e,u){r[e]=t(n,e,u)}),r},v.max=Rt,v.memoize=function(n,t){function e(){var r=e.cache,u=t?t.apply(this,arguments):b+arguments[0];return xe.call(r,u)?r[u]:r[u]=n.apply(this,arguments) -}if(!xt(n))throw new ce;return e.cache={},e},v.merge=function(n){var t=arguments,e=2;if(!Ct(n))return n;if("number"!=typeof t[2]&&(e=t.length),3e?Re(0,r+e):Fe(e,r-1))+1);r--;)if(n[r]===t)return r; -return-1},v.mixin=Xt,v.noConflict=function(){return e._=ve,this},v.noop=Yt,v.now=fr,v.parseInt=cr,v.random=function(n,t,e){var r=null==n,u=null==t;return null==e&&(typeof n=="boolean"&&u?(e=n,n=1):u||typeof t!="boolean"||(e=t,u=true)),r&&u&&(t=1),n=+n||0,u?(t=n,n=0):t=+t||0,e||n%1||t%1?(e=Te(),Fe(n+e*(t-n+parseFloat("1e-"+((e+"").length-1))),t)):ct(n,t)},v.reduce=Ft,v.reduceRight=$t,v.result=function(n,t){if(n){var e=n[t];return xt(e)?n[t]():e}},v.runInContext=g,v.size=function(n){var t=n?n.length:0; -return typeof t=="number"?t:Je(n).length},v.some=Lt,v.sortedIndex=Wt,v.template=function(n,t,e){var r=v.templateSettings;n=fe(n||""),e=tr({},e,r);var u,o=tr({},e.imports,r.imports),r=Je(o),o=Ot(o),i=0,l=e.interpolate||N,f="__p+='",l=le((e.escape||N).source+"|"+l.source+"|"+(l===A?O:N).source+"|"+(e.evaluate||N).source+"|$","g");n.replace(l,function(t,e,r,o,l,c){return r||(r=o),f+=n.slice(i,c).replace(P,a),e&&(f+="'+__e("+e+")+'"),l&&(u=true,f+="';"+l+";\n__p+='"),r&&(f+="'+((__t=("+r+"))==null?'':__t)+'"),i=c+t.length,t +return n},v.range=function(n,t,e){n=+n||0,e=typeof e=="number"?e:+e||1,null==t&&(t=n,n=0);var r=-1;t=Re(0,de((t-n)/(e||1)));for(var u=te(t);++re?Re(0,r+e):Fe(e,r-1))+1);r--;)if(n[r]===t)return r;return-1},v.mixin=Xt,v.noConflict=function(){return e._=ve,this},v.noop=Yt,v.now=fr,v.parseInt=cr,v.random=function(n,t,e){var r=null==n,u=null==t;return null==e&&(typeof n=="boolean"&&u?(e=n,n=1):u||typeof t!="boolean"||(e=t,u=true)),r&&u&&(t=1),n=+n||0,u?(t=n,n=0):t=+t||0,e||n%1||t%1?(e=$e(),Fe(n+e*(t-n+parseFloat("1e-"+((e+"").length-1))),t)):ct(n,t) +},v.reduce=Ft,v.reduceRight=Tt,v.result=function(n,t){if(n){var e=n[t];return xt(e)?n[t]():e}},v.runInContext=g,v.size=function(n){var t=n?n.length:0;return typeof t=="number"?t:Je(n).length},v.some=Lt,v.sortedIndex=Wt,v.template=function(n,t,e){var r=v.templateSettings;n=fe(n||""),e=tr({},e,r);var u,o=tr({},e.imports,r.imports),r=Je(o),o=Ot(o),i=0,l=e.interpolate||N,f="__p+='",l=le((e.escape||N).source+"|"+l.source+"|"+(l===A?O:N).source+"|"+(e.evaluate||N).source+"|$","g");n.replace(l,function(t,e,r,o,l,c){return r||(r=o),f+=n.slice(i,c).replace(P,a),e&&(f+="'+__e("+e+")+'"),l&&(u=true,f+="';"+l+";\n__p+='"),r&&(f+="'+((__t=("+r+"))==null?'':__t)+'"),i=c+t.length,t }),f+="';",l=e=e.variable,l||(e="obj",f="with("+e+"){"+f+"}"),f=(u?f.replace(x,""):f).replace(C,"$1").replace(E,"$1;"),f="function("+e+"){"+(l?"":e+"||("+e+"={});")+"var __t,__p='',__e=_.escape"+(u?",__j=Array.prototype.join;function print(){__p+=__j.call(arguments,'')}":";")+f+"return __p}";try{var c=ue(r,"return "+f).apply(h,o)}catch(p){throw p.source=f,p}return t?c(t):(c.source=f,c)},v.unescape=function(n){return null==n?"":fe(n).replace(Xe,dt)},v.uniqueId=function(n){var t=++m;return fe(null==n?"":n)+t -},v.all=It,v.any=Lt,v.detect=Dt,v.findWhere=Dt,v.foldl=Ft,v.foldr=$t,v.include=St,v.inject=Ft,rr(v,function(n,t){v.prototype[t]||(v.prototype[t]=function(){var t=[this.__wrapped__],e=this.__chain__;return Ce.apply(t,arguments),t=n.apply(v,t),e?new y(t,e):t})}),v.first=zt,v.last=function(n,t,e){var r=0,u=n?n.length:0;if(typeof t!="number"&&null!=t){var o=u;for(t=v.createCallback(t,e,3);o--&&t(n[o],o,n);)r++}else if(r=t,null==r||e)return n?n[u-1]:h;return s(n,Re(0,u-r))},v.sample=function(n,t,e){return n&&typeof n.length!="number"?n=Ot(n):qe.unindexedChars&&Et(n)&&(n=n.split("")),null==t||e?n?n[ct(0,n.length-1)]:h:(n=Tt(n),n.length=Fe(Re(0,t),n.length),n) +},v.all=It,v.any=Lt,v.detect=Dt,v.findWhere=Dt,v.foldl=Ft,v.foldr=Tt,v.include=St,v.inject=Ft,rr(v,function(n,t){v.prototype[t]||(v.prototype[t]=function(){var t=[this.__wrapped__],e=this.__chain__;return Ce.apply(t,arguments),t=n.apply(v,t),e?new y(t,e):t})}),v.first=zt,v.last=function(n,t,e){var r=0,u=n?n.length:0;if(typeof t!="number"&&null!=t){var o=u;for(t=v.createCallback(t,e,3);o--&&t(n[o],o,n);)r++}else if(r=t,null==r||e)return n?n[u-1]:h;return s(n,Re(0,u-r))},v.sample=function(n,t,e){return n&&typeof n.length!="number"?n=Ot(n):qe.unindexedChars&&Et(n)&&(n=n.split("")),null==t||e?n?n[ct(0,n.length-1)]:h:(n=$t(n),n.length=Fe(Re(0,t),n.length),n) },v.take=zt,v.head=zt,rr(v,function(n,t){var e="sample"!==t;v.prototype[t]||(v.prototype[t]=function(t,r){var u=this.__chain__,o=n(this.__wrapped__,t,r);return u||null!=t&&(!r||e&&typeof t=="function")?new y(o,u):o})}),v.VERSION="2.3.0",v.prototype.chain=function(){return this.__chain__=true,this},v.prototype.toString=function(){return fe(this.__wrapped__)},v.prototype.value=ne,v.prototype.valueOf=ne,Ze(["join","pop","shift"],function(n){var t=pe[n];v.prototype[n]=function(){var n=this.__chain__,e=t.apply(this.__wrapped__,arguments); return n?new y(e,n):e}}),Ze(["push","reverse","sort","unshift"],function(n){var t=pe[n];v.prototype[n]=function(){return t.apply(this.__wrapped__,arguments),this}}),Ze(["concat","slice","splice"],function(n){var t=pe[n];v.prototype[n]=function(){return new y(t.apply(this.__wrapped__,arguments),this.__chain__)}}),qe.spliceObjects||Ze(["pop","shift","splice"],function(n){var t=pe[n],e="splice"==n;v.prototype[n]=function(){var n=this.__chain__,r=this.__wrapped__,u=t.apply(r,arguments);return 0===r.length&&delete r[0],n||e?new y(u,n):u -}}),v}var h,v=[],y=[],m=0,d={},b=+new Date+"",_=75,w=40,j=" \t\x0B\f\xa0\ufeff\n\r\u2028\u2029\u1680\u180e\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u202f\u205f\u3000",x=/\b__p\+='';/g,C=/\b(__p\+=)''\+/g,E=/(__e\(.*?\)|\b__t\))\+'';/g,O=/\$\{([^\\}]*(?:\\.[^\\}]*)*)\}/g,S=/\w*$/,I=/^\s*function[ \n\r\t]+\w/,A=/<%=([\s\S]+?)%>/g,D=RegExp("^["+j+"]*0+(?=.$)"),N=/($^)/,B=/\bthis\b/,P=/['\n\r\t\u2028\u2029\\]/g,R="Array Boolean Date Error Function Math Number Object RegExp String _ attachEvent clearTimeout isFinite isNaN parseInt setImmediate setTimeout".split(" "),F="constructor hasOwnProperty isPrototypeOf propertyIsEnumerable toLocaleString toString valueOf".split(" "),$="[object Arguments]",T="[object Array]",L="[object Boolean]",z="[object Date]",q="[object Error]",K="[object Function]",W="[object Number]",G="[object Object]",J="[object RegExp]",M="[object String]",V={}; -V[K]=false,V[$]=V[T]=V[L]=V[z]=V[W]=V[G]=V[J]=V[M]=true;var H={leading:false,maxWait:0,trailing:false},U={configurable:false,enumerable:false,value:null,writable:false},Q={a:"",b:null,c:"",d:"",e:"",v:null,g:"",h:null,support:null,i:"",j:false},X={"boolean":false,"function":true,object:true,number:false,string:false,undefined:false},Y={"\\":"\\","'":"'","\n":"n","\r":"r","\t":"t","\u2028":"u2028","\u2029":"u2029"},Z=X[typeof window]&&window||this,nt=X[typeof exports]&&exports&&!exports.nodeType&&exports,tt=X[typeof module]&&module&&!module.nodeType&&module,et=tt&&tt.exports===nt&&nt,rt=X[typeof global]&&global; +}}),v}var h,v=[],y=[],m=0,d={},b=+new Date+"",_=75,w=40,j=" \t\x0B\f\xa0\ufeff\n\r\u2028\u2029\u1680\u180e\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u202f\u205f\u3000",x=/\b__p\+='';/g,C=/\b(__p\+=)''\+/g,E=/(__e\(.*?\)|\b__t\))\+'';/g,O=/\$\{([^\\}]*(?:\\.[^\\}]*)*)\}/g,S=/\w*$/,I=/^\s*function[ \n\r\t]+\w/,A=/<%=([\s\S]+?)%>/g,D=RegExp("^["+j+"]*0+(?=.$)"),N=/($^)/,B=/\bthis\b/,P=/['\n\r\t\u2028\u2029\\]/g,R="Array Boolean Date Error Function Math Number Object RegExp String _ attachEvent clearTimeout isFinite isNaN parseInt setImmediate setTimeout".split(" "),F="constructor hasOwnProperty isPrototypeOf propertyIsEnumerable toLocaleString toString valueOf".split(" "),T="[object Arguments]",$="[object Array]",L="[object Boolean]",z="[object Date]",q="[object Error]",K="[object Function]",W="[object Number]",G="[object Object]",J="[object RegExp]",M="[object String]",V={}; +V[K]=false,V[T]=V[$]=V[L]=V[z]=V[W]=V[G]=V[J]=V[M]=true;var H={leading:false,maxWait:0,trailing:false},U={configurable:false,enumerable:false,value:null,writable:false},Q={a:"",b:null,c:"",d:"",e:"",v:null,g:"",h:null,support:null,i:"",j:false},X={"boolean":false,"function":true,object:true,number:false,string:false,undefined:false},Y={"\\":"\\","'":"'","\n":"n","\r":"r","\t":"t","\u2028":"u2028","\u2029":"u2029"},Z=X[typeof window]&&window||this,nt=X[typeof exports]&&exports&&!exports.nodeType&&exports,tt=X[typeof module]&&module&&!module.nodeType&&module,et=tt&&tt.exports===nt&&nt,rt=X[typeof global]&&global; !rt||rt.global!==rt&&rt.window!==rt||(Z=rt);var ut=g();typeof define=="function"&&typeof define.amd=="object"&&define.amd?(Z._=ut, define(function(){return ut})):nt&&tt?et?(tt.exports=ut)._=ut:nt._=ut:Z._=ut}).call(this); \ No newline at end of file diff --git a/dist/lodash.js b/dist/lodash.js index af48867e3..17ece3301 100644 --- a/dist/lodash.js +++ b/dist/lodash.js @@ -256,22 +256,29 @@ */ function compareAscending(a, b) { var ac = a.criteria, - bc = b.criteria; + bc = b.criteria, + index = -1, + length = ac.length; - // ensure a stable sort in V8 and other engines - // http://code.google.com/p/v8/issues/detail?id=90 - if (ac !== bc) { - if (ac > bc || typeof ac == 'undefined') { - return 1; - } - if (ac < bc || typeof bc == 'undefined') { - return -1; + while (++index < length) { + var value = ac[index], + other = bc[index]; + + if (value !== other) { + if (value > other || typeof value == 'undefined') { + return 1; + } + if (value < other || typeof other == 'undefined') { + return -1; + } } } - // The JS engine embedded in Adobe applications like InDesign has a buggy - // `Array#sort` implementation that causes it, under certain circumstances, - // to return the same value for `a` and `b`. - // See https://github.com/jashkenas/underscore/pull/1247 + // Fixes an `Array#sort` bug in the JS engine embedded in Adobe applications + // that causes it, under certain circumstances, to return the same value for + // `a` and `b`. See https://github.com/jashkenas/underscore/pull/1247 + // + // This also ensures a stable sort in V8 and other engines. + // See http://code.google.com/p/v8/issues/detail?id=90 return a.index - b.index; } @@ -3953,6 +3960,9 @@ * If a property name is provided for `callback` the created "_.pluck" style * callback will return the property value of the given element. * + * If an array of property names is provided for `callback` the collection + * will be sorted by each property value. + * * 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`. @@ -3961,7 +3971,7 @@ * @memberOf _ * @category Collections * @param {Array|Object|string} collection The collection to iterate over. - * @param {Function|Object|string} [callback=identity] The function called + * @param {Array|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`. @@ -3974,19 +3984,37 @@ * _.sortBy([1, 2, 3], function(num) { return this.sin(num); }, Math); * // => [3, 1, 2] * + * var characters = [ + * { 'name': 'barney', 'age': 36 }, + * { 'name': 'fred', 'age': 40 }, + * { 'name': 'barney', 'age': 26 }, + * { 'name': 'fred', 'age': 30 } + * ]; + * * // using "_.pluck" callback shorthand - * _.sortBy(['banana', 'strawberry', 'apple'], 'length'); - * // => ['apple', 'banana', 'strawberry'] + * _.map(_.sortBy(characters, 'age'), _.values); + * // => [['barney', 26], ['fred', 30], ['barney', 36], ['fred', 40]] + * + * // sorting by multiple properties + * _.map(_.sortBy(characters, ['name', 'age']), _.values); + * // = > [['barney', 26], ['barney', 36], ['fred', 30], ['fred', 40]] */ function sortBy(collection, callback, thisArg) { var index = -1, + isArr = isArray(callback), length = collection ? collection.length : 0, result = Array(typeof length == 'number' ? length : 0); - callback = lodash.createCallback(callback, thisArg, 3); + if (!isArr) { + callback = lodash.createCallback(callback, thisArg, 3); + } forEach(collection, function(value, key, collection) { var object = result[++index] = getObject(); - object.criteria = callback(value, key, collection); + if (isArr) { + object.criteria = map(callback, function(key) { return value[key]; }); + } else { + (object.criteria = getArray())[0] = callback(value, key, collection); + } object.index = index; object.value = value; }); @@ -3996,6 +4024,9 @@ while (length--) { var object = result[length]; result[length] = object.value; + if (!isArr) { + releaseArray(object.criteria); + } releaseObject(object); } return result; @@ -5846,7 +5877,7 @@ * _.capitalize('fred'); * // => 'Fred' * - * _('fred').capitalize(); + * _('fred').capitalize().value(); * // => 'Fred' */ function mixin(object, source) { diff --git a/dist/lodash.min.js b/dist/lodash.min.js index 707c4e634..28eb0b7ff 100644 --- a/dist/lodash.min.js +++ b/dist/lodash.min.js @@ -4,11 +4,11 @@ * Build: `lodash modern -o ./dist/lodash.js` */ ;(function(){function n(n,t,e){e=(e||0)-1;for(var r=n?n.length:0;++er||typeof e=="undefined")return 1;if(ee?0:e);++ri||typeof a=="undefined")return 1;if(ae?0:e);++r=_&&a===n,l=[];if(f){var p=o(r);p?(a=t,r=p):f=false}for(;++ua(r,p)&&l.push(p);return f&&c(r),l}function it(n,t,e,r){r=(r||0)-1;for(var u=n?n.length:0,o=[];++r bc || typeof ac == 'undefined') { - return 1; - } - if (ac < bc || typeof bc == 'undefined') { - return -1; + while (++index < length) { + var value = ac[index], + other = bc[index]; + + if (value !== other) { + if (value > other || typeof value == 'undefined') { + return 1; + } + if (value < other || typeof other == 'undefined') { + return -1; + } } } - // The JS engine embedded in Adobe applications like InDesign has a buggy - // `Array#sort` implementation that causes it, under certain circumstances, - // to return the same value for `a` and `b`. - // See https://github.com/jashkenas/underscore/pull/1247 + // Fixes an `Array#sort` bug in the JS engine embedded in Adobe applications + // that causes it, under certain circumstances, to return the same value for + // `a` and `b`. See https://github.com/jashkenas/underscore/pull/1247 + // + // This also ensures a stable sort in V8 and other engines. + // See http://code.google.com/p/v8/issues/detail?id=90 return a.index - b.index; } @@ -2734,6 +2741,9 @@ * If a property name is provided for `callback` the created "_.pluck" style * callback will return the property value of the given element. * + * If an array of property names is provided for `callback` the collection + * will be sorted by each property value. + * * 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`. @@ -2742,7 +2752,7 @@ * @memberOf _ * @category Collections * @param {Array|Object|string} collection The collection to iterate over. - * @param {Function|Object|string} [callback=identity] The function called + * @param {Array|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`. @@ -2755,9 +2765,20 @@ * _.sortBy([1, 2, 3], function(num) { return this.sin(num); }, Math); * // => [3, 1, 2] * + * var characters = [ + * { 'name': 'barney', 'age': 36 }, + * { 'name': 'fred', 'age': 40 }, + * { 'name': 'barney', 'age': 26 }, + * { 'name': 'fred', 'age': 30 } + * ]; + * * // using "_.pluck" callback shorthand - * _.sortBy(['banana', 'strawberry', 'apple'], 'length'); - * // => ['apple', 'banana', 'strawberry'] + * _.map(_.sortBy(characters, 'age'), _.values); + * // => [['barney', 26], ['fred', 30], ['barney', 36], ['fred', 40]] + * + * // sorting by multiple properties + * _.map(_.sortBy(characters, ['name', 'age']), _.values); + * // = > [['barney', 26], ['barney', 36], ['fred', 30], ['fred', 40]] */ function sortBy(collection, callback, thisArg) { var index = -1, @@ -2767,7 +2788,7 @@ callback = createCallback(callback, thisArg, 3); forEach(collection, function(value, key, collection) { result[++index] = { - 'criteria': callback(value, key, collection), + 'criteria': [callback(value, key, collection)], 'index': index, 'value': value }; @@ -4233,7 +4254,7 @@ * _.capitalize('fred'); * // => 'Fred' * - * _('fred').capitalize(); + * _('fred').capitalize().value(); * // => 'Fred' */ function mixin(object) { diff --git a/dist/lodash.underscore.min.js b/dist/lodash.underscore.min.js index e4a46655c..b239a89e1 100644 --- a/dist/lodash.underscore.min.js +++ b/dist/lodash.underscore.min.js @@ -3,7 +3,7 @@ * Lo-Dash 2.3.0 (Custom Build) lodash.com/license | Underscore.js 1.5.2 underscorejs.org/LICENSE * Build: `lodash underscore exports="amd,commonjs,global,node" -o ./dist/lodash.underscore.js` */ -;(function(){function n(n,r,t){t=(t||0)-1;for(var e=n?n.length:0;++te||typeof t=="undefined")return 1;if(tt?0:t);++ef||typeof i=="undefined")return 1;if(it?0:t);++ee(r,i)&&o.push(i)}return o}function p(n,r,t,e){e=(e||0)-1;for(var u=n?n.length:0,o=[];++ei(a,e)){for(r=t;--r;)if(0>i(n[r],e))continue n;a.push(e)}return a},u.invert=x,u.invoke=function(n,r){var t=e(arguments,2),u=-1,o=typeof r=="function",i=n?n.length:0,f=Array(typeof i=="number"?i:0);return q(n,function(n){f[++u]=(o?r:n[r]).apply(n,t)}),f},u.keys=Pr,u.map=I,u.max=M,u.memoize=function(n,r){var t={};return function(){var e=r?r.apply(this,arguments):er+arguments[0];return Sr.call(t,e)?t[e]:t[e]=n.apply(this,arguments) }},u.min=function(n,r,t){var e=1/0,u=e;typeof r!="function"&&t&&t[r]===n&&(r=null);var o=-1,i=n?n.length:0;if(null==r&&typeof i=="number")for(;++or?0:r);++nr?0:r);++nt?Ir(0,e+t):Mr(t,e-1))+1);e--;)if(n[e]===r)return e; return-1},u.mixin=Y,u.noConflict=function(){return yr._=xr,this},u.random=function(n,r){return null==n&&null==r&&(r=1),n=+n||0,null==r?(r=n,n=0):r=+r||0,n+Or($r()*(r-n+1))},u.reduce=$,u.reduceRight=W,u.result=function(n,r){if(n){var t=n[r];return E(t)?n[r]():t}},u.size=function(n){var r=n?n.length:0;return typeof r=="number"?r:Pr(n).length},u.some=C,u.sortedIndex=H,u.template=function(n,r,e){var o=u,i=o.templateSettings;n=(n||"")+"",e=w({},e,i);var f=0,a="__p+='",i=e.variable;n.replace(RegExp((e.escape||ur).source+"|"+(e.interpolate||ur).source+"|"+(e.evaluate||ur).source+"|$","g"),function(r,e,u,o,i){return a+=n.slice(f,i).replace(or,t),e&&(a+="'+_.escape("+e+")+'"),o&&(a+="';"+o+";\n__p+='"),u&&(a+="'+((__t=("+u+"))==null?'':__t)+'"),f=i+r.length,r diff --git a/lodash.js b/lodash.js index 87663c8df..e37003790 100644 --- a/lodash.js +++ b/lodash.js @@ -280,22 +280,29 @@ */ function compareAscending(a, b) { var ac = a.criteria, - bc = b.criteria; + bc = b.criteria, + index = -1, + length = ac.length; - // ensure a stable sort in V8 and other engines - // http://code.google.com/p/v8/issues/detail?id=90 - if (ac !== bc) { - if (ac > bc || typeof ac == 'undefined') { - return 1; - } - if (ac < bc || typeof bc == 'undefined') { - return -1; + while (++index < length) { + var value = ac[index], + other = bc[index]; + + if (value !== other) { + if (value > other || typeof value == 'undefined') { + return 1; + } + if (value < other || typeof other == 'undefined') { + return -1; + } } } - // The JS engine embedded in Adobe applications like InDesign has a buggy - // `Array#sort` implementation that causes it, under certain circumstances, - // to return the same value for `a` and `b`. - // See https://github.com/jashkenas/underscore/pull/1247 + // Fixes an `Array#sort` bug in the JS engine embedded in Adobe applications + // that causes it, under certain circumstances, to return the same value for + // `a` and `b`. See https://github.com/jashkenas/underscore/pull/1247 + // + // This also ensures a stable sort in V8 and other engines. + // See http://code.google.com/p/v8/issues/detail?id=90 return a.index - b.index; } @@ -4319,6 +4326,9 @@ * If a property name is provided for `callback` the created "_.pluck" style * callback will return the property value of the given element. * + * If an array of property names is provided for `callback` the collection + * will be sorted by each property value. + * * 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`. @@ -4327,7 +4337,7 @@ * @memberOf _ * @category Collections * @param {Array|Object|string} collection The collection to iterate over. - * @param {Function|Object|string} [callback=identity] The function called + * @param {Array|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`. @@ -4340,19 +4350,37 @@ * _.sortBy([1, 2, 3], function(num) { return this.sin(num); }, Math); * // => [3, 1, 2] * + * var characters = [ + * { 'name': 'barney', 'age': 36 }, + * { 'name': 'fred', 'age': 40 }, + * { 'name': 'barney', 'age': 26 }, + * { 'name': 'fred', 'age': 30 } + * ]; + * * // using "_.pluck" callback shorthand - * _.sortBy(['banana', 'strawberry', 'apple'], 'length'); - * // => ['apple', 'banana', 'strawberry'] + * _.map(_.sortBy(characters, 'age'), _.values); + * // => [['barney', 26], ['fred', 30], ['barney', 36], ['fred', 40]] + * + * // sorting by multiple properties + * _.map(_.sortBy(characters, ['name', 'age']), _.values); + * // = > [['barney', 26], ['barney', 36], ['fred', 30], ['fred', 40]] */ function sortBy(collection, callback, thisArg) { var index = -1, + isArr = isArray(callback), length = collection ? collection.length : 0, result = Array(typeof length == 'number' ? length : 0); - callback = lodash.createCallback(callback, thisArg, 3); + if (!isArr) { + callback = lodash.createCallback(callback, thisArg, 3); + } forEach(collection, function(value, key, collection) { var object = result[++index] = getObject(); - object.criteria = callback(value, key, collection); + if (isArr) { + object.criteria = map(callback, function(key) { return value[key]; }); + } else { + (object.criteria = getArray())[0] = callback(value, key, collection); + } object.index = index; object.value = value; }); @@ -4362,6 +4390,9 @@ while (length--) { var object = result[length]; result[length] = object.value; + if (!isArr) { + releaseArray(object.criteria); + } releaseObject(object); } return result; diff --git a/test/saucelabs.js b/test/saucelabs.js index 9d3a6cc22..e32e0034b 100644 --- a/test/saucelabs.js +++ b/test/saucelabs.js @@ -74,8 +74,8 @@ ['Windows 7', 'internet explorer', '8'], ['Windows XP', 'internet explorer', '7'], ['Windows XP', 'internet explorer', '6'], - ['Windows 7', 'opera', '12'], - ['Windows 7', 'opera', '11'], + //['Windows 7', 'opera', '12'], + //['Windows 7', 'opera', '11'], ['OS X 10.8', 'safari', '6'], ['Windows 7', 'safari', '5'], ['Windows XP', 'safari', '4'] diff --git a/test/test.js b/test/test.js index 4be6f09b8..97d005d56 100644 --- a/test/test.js +++ b/test/test.js @@ -6512,6 +6512,18 @@ deepEqual(actual, [3, 1, 2]); }); + test('should work with an array for `callback`', 1, function() { + var objects = [ + { 'a': 'x', 'b': 3 }, + { 'a': 'y', 'b': 4 }, + { 'a': 'x', 'b': 1 }, + { 'a': 'y', 'b': 2 } + ]; + + var actual = _.sortBy(objects, ['a', 'b']); + deepEqual(actual, [objects[2], objects[0], objects[3], objects[1]]); + }); + test('should work with a string for `callback`', 1, function() { var actual = _.pluck(_.sortBy(objects, 'num'), 'num'); deepEqual(actual, [0, 11, 16, 74, 212, 991, 1515]);