1

I'm trying to .sort() an array of objects, but my javascript knowledge isn't strong enough to rewrite the comparator function to accept an arrow function to find the key on the objects rather than use a string. Any help refactoring this would be appreciated:

My comparison function:

compareValues = (key, order = "ascending") => {
      let result = 0;

      return function(lhs, rhs) {
        if (!(lhs.hasOwnProperty(key) && rhs.hasOwnProperty(key))) {
          return result; // property is missing; comparison is impossible
        }

        const l = lhs[key].toLowerCase() || lhs[key];
        const r = rhs[key].toLowerCase() || rhs[key];

        result = (l > r) ? 1 : (l < r) ? -1 : 0;

        return result * (order === "ascending") ? 1 : -1;
      };
    };

which is used in the conventional way:

objects.sort(compareValues("name")); // or
objects.sort(compareValues("name", descending));

The goal is to be able to use it thusly:

objects.sort(compareValues(o => o.name));

... but frankly I haven't used JS much until lately, so I suck at it.

4
  • javascript doesnt have c# with lambda expression trees. Commented Mar 6, 2020 at 16:52
  • Are you saying you want to be able to pass a comparator function into compareValues? Based on your function's signature, it expects a key, which looks like it's a string, but you're trying to pass a function instead. Commented Mar 6, 2020 at 16:55
  • Check key in compareValues. If it's a function, run it, and use that as the key to look up. If it isn't a function use it as the key. Commented Mar 6, 2020 at 16:55
  • @DanielA.White But it's not necessary. That's the power of first-class functions: they are first-class and don't need to be handled in an OO manner Commented Mar 6, 2020 at 17:14

3 Answers 3

2

Maybe something like:

const compareValues = (pickProp, order = 'ascending') => {
    let result = 0

    return (lhs, rhs) => {
        const l = pickProp(lhs) // pickProp is passed #first-class
        const r = pickProp(rhs)
        if (!l && !r) {
            return 0 // Quick callout here, comparators only ever return -1, 0, or 1.
        }

        result = l > r ? 1 : l < r ? -1 : 0

        // Leveraging your default values here for cleaner signature
        return result * (order === 'ascending') ? 1 : -1
    }
}

list.sort(compareValues(o => o.name))
// or even 
list.sort(compareValues(o => o.name), 'descending')

I believe thats in-line with your question.

Sign up to request clarification or add additional context in comments.

3 Comments

A little comment explaining how it works would be great. I don't mean comment every line, just bring attention to the core idea of a picker function
Yea sure. One sec.
Updated, let me know if you want something else.
0

I don't think you need to perform checks on objects to see if they have specific properties because you would know for sure. So this is how I see it.


const comparer= (select, descend = false) => (a, b) => {
    let lhs = select(a); let rhs = select(b);
    if (lhs < rhs) return descend ? 1 : -1;
    if (lhs > rhs) return descend ? -1 : 1;
    return 0;
}

let arr = [{ id: 1, name: "Clara" }, { id: 2, name: "Abraham" }, { id: 3, name: "Brian" }]

arr.sort(comparer(o => o.name))
console.log(arr);

arr.sort(comparer(o => o.name, true))
console.log(arr);

Comments

0

I think the closer you can get with what you want is this:

let compareValues = (key, order = "ascending") => {
  let result = 0;

  return function(lhs, rhs) {
    if (!(key(lhs) && key(rhs))) {
      return result; // property is invalid; comparison is impossible
    }

    const l = key(lhs).toLowerCase() || key(lhs);
    const r = key(rhs).toLowerCase() || key(rhs);

    result = (l > r) ? 1 : (l < r) ? -1 : 0;

    return result * (order === "ascending") ? 1 : -1;
  };
};

let objects = [{
  "name": "Mary"
}, {
  "name": "John"
}];

objects.sort(compareValues(o => o.name));

console.log(objects);

4 Comments

Your code doesn't work. The objects are in the same order they went in.
@ScottBaker to me the snippet's console shows: John, Mary.
I see Mary, John
@ScottBaker tested in Chrome and indeed, it displays Mary, John. In FF it doesn't.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.