Array#sort(prop)
Brendan Eich
brendan at mozilla.com
Sun Apr 1 21:59:44 PDT 2012
Ok, easy goof (I was boarding a plane -- that's my excuse!). But easy to
fix too.
Point is, as Peter posted, this is hard to get right if one has to write
it from scratch. Finding and downloading a standard library? Why not
make that the built-in all implementations provide?
/be
Mark S. Miller wrote:
>
>
> On Sun, Apr 1, 2012 at 6:56 PM, Mark S. Miller <erights at google.com
> <mailto:erights at google.com>> wrote:
>
>
>
> On Sun, Apr 1, 2012 at 3:53 PM, Brendan Eich <brendan at mozilla.org
> <mailto:brendan at mozilla.org>> wrote:
>
>
> arr.sort((a, b) => (a.prop< b.prop) ?-1 : (a.prop> b.prop)
> ? 1 : 0);
>
>
> and if you weed out NaN to avoid the comparison function
> returning NaN, while taking advantage of the fact that the
> return value's sign is all that matters, not exact {-1, 0, 1}
> membership, then it's not much worse:
>
>
> arr.sort((a, b) => { let t = a.prop - b.prop; return (t !==
> t) ? 0 : t; });
>
>
>
> Quoting from <http://es5.github.com/#x15.4.4.11>, the requirements
> on the comparefn are:
>
> A function /comparefn/ is a consistent comparison function
> for a set of values /S/ if all of the requirements below
> are met for all values /a/, /b/, and /c/ (possibly the
> same value) in the set /S/: The notation /a/ <_CF
> /b/ means /comparefn/(/a/,/b/) < 0; /a/ =_CF /b/ means
> /comparefn/(/a/,/b/) = 0 (of either sign); and/a/ >_CF
> /b/ means /comparefn/(/a/,/b/) > 0.
>
> Calling /comparefn/(/a/,/b/) always returns the same value
> /v/ when given a specific pair of values /a/and /b/ as its
> two arguments. Furthermore, Type
> <http://es5.github.com/#Type>(/v/) is Number, and /v/ is
> not NaN. Note that this implies that exactly one of /a/
> <_CF /b/, /a/ =_CF /b/, and /a/ >_CF /b/ will be true for
> a given pair of /a/ and /b/.
>
> Calling /comparefn/(/a/,/b/) does not modify the
> *this* object.
>
> /a/ =_CF /a/ (reflexivity)
>
> If /a/ =_CF /b/, then /b/ =_CF /a/ (symmetry)
>
> If /a/ =_CF /b/ and /b/ =_CF /c/, then /a/ =_CF
> /c/ (transitivity of =_CF )
>
> If /a/ <_CF /b/ and /b/ <_CF /c/, then /a/ <_CF
> /c/ (transitivity of <_CF )
>
> If /a/ >_CF /b/ and /b/ >_CF /c/, then /a/ >_CF
> /c/ (transitivity of >_CF )
>
> *NOTE*
>
> The above conditions are necessary and sufficient to
> ensure that /comparefn/ divides the set/S/ into
> equivalence classes and that these equivalence classes are
> totally ordered.
>
>
> If sort is called with a comparefn which violates this constraint,
> according to normative text
>
> If /comparefn/ is not *undefined* and is not a consistent
> comparison function for the elements of this array
> <http://es5.github.com/#array-element> (see below), the
> behaviour of |*sort*| is implementation-defined.
>
>
> a conforming implementation may kill the user, lose memory safety,
> or launch the nukes.
>
> Since in this note we're not concerned about new syntax but rather
> the notion of "implementation-defined", let's rewrite Brendan's
> two sort functions in ES5:
>
>
> function c1(a, b) {
> return a < b ? -1 : a > b ? 1 : 0;
> }
> function c2(a, b) {
> var t = a - b;
> return t !== t ? 0 : 1;
>
>
> Oops, typo. The "1" immediately above should be "t". But this doesn't
> affect the point.
>
> }
>
> Both of these violate transitivity of =_CF
>
> c1(3,NaN);
> 0
> c1(NaN,4);
> 0
> c1(3,4);
> -1
> c2(3,NaN)
> 0
> c2(NaN,4)
> 0
> c2(3,4)
> 1
>
>
> Fortunately, I have not tried passing either of these to sort, and
> so have lived to tell the tale.
>
> Let's kill "implementation-defined" rather than our users.
>
>
>
> I'm assuming you don't need to sort -0< 0 (which evaluates to
> false in JS).
>
> Another observation: this last version is the only one that
> avoids multiple implicit conversions via toString or valueOf
> of an object operand, if one or both of a and b is an object
> and the first condition (a.prop< b.prop) evaluates to false.
> This means the only portable form is the last version.
>
> Yeah, it's a pain to write every time and people will mess up
> the NaN corner case. A standard built-in would be good. But
> why use a string parameter key instead of just a built-in
> function?
>
> /be
>
>
> _______________________________________________
> es-discuss mailing list
> es-discuss at mozilla.org <mailto:es-discuss at mozilla.org>
> https://mail.mozilla.org/listinfo/es-discuss
>
>
>
>
> --
> Cheers,
> --MarkM
>
>
>
>
> --
> Cheers,
> --MarkM
> _______________________________________________
> es-discuss mailing list
> es-discuss at mozilla.org
> https://mail.mozilla.org/listinfo/es-discuss
More information about the es-discuss
mailing list