1

I am trying to create a sorting function that sorts a nested array of objects while giving a key dynamically (with different depths).

sortByKey(array, key){
    var splitKey = key.split(".");
    if(splitKey.length = 2){
      return array.sort(function(a, b) {
        var x = a[splitKey[0]][splitKey[1]]; var y = b[splitKey[0]][splitKey[1]];
        return ((x < y) ? -1 : ((x > y) ? 1 : 0));
      });
    } else {
      return array.sort(function(a, b) {
        var x = a[key]; var y = b[key];
        return ((x < y) ? -1 : ((x > y) ? 1 : 0));
      });
    }
  }

I want to get rid of the if - else and use a for loop instead. The goal is that the function works with 'name', 'name.first' and 'name.first.another' (as an example). Is there a way to do this dynamically?

In other words, I want to use the same function with different arrays. So with one array I want to sort it calling sortByKey(array1, 'name') and with another sortByKey(array2, 'location.address') and maybe with a third sortByKey(array3, 'location.address.postalcode') or something like that.

2
  • if(splitKey.length = 2) is unlikely to do what you think. Commented Aug 18, 2016 at 12:44
  • 1
    can you provide an example of what ur trying to accomplish ? Commented Aug 18, 2016 at 12:46

3 Answers 3

4

Extract property extracting function

function prop(key) {
  var keys = key.split('.');

  return keys.reduce.bind(keys, function(obj, name) {
    return obj[name]
  })
}

and use it to well extract values :)

sortByKey(array, key){
    var getKey = prop(key);

    return array.sort(function(a, b){
      var x = getKey(a); var y = getKey(b);
        return ((x < y) ? -1 : ((x > y) ? 1 : 0));
    })
  }
Sign up to request clarification or add additional context in comments.

9 Comments

This solution is so simple and elegant that deserves more up votes :)
.reduce.bind() (and subsequently getKey()) — Thank you for showing a good example of currying!
bind is not necessary here. it is superfluous and irritating. what is the actual purpose of this?
@NinaScholz "it is superfluous and irritating" well, it is your opinion. Bind wasn't that irritating back in 2016 when arrow functions required transpilation.
bind was neither back in time not neccessary nor today. ther is no use of this.
|
0

I think you mean something like this:

function sortByKey(array, key){
    var splitKey = key.split(".");

    return array.sort(function(a, b) {
        var ta = a;
        var tb = b;
        for (var i=0; i<splitKey.length; i++) {
            ta = ta[splitKey[i]];
        };
        /// return ((a < b) ? -1 : ((a > b) ? 1 : 0)); // Too complex ;-)
        return a - b;

    });

};

Comments

0

Your problem is a misused assignment, where it should be a comparison.

if (splitKey.length === 2) {
//                  ^^^

A shorter approach could use Array#reduce.

function sortByKey(array, key) {
    var getValue = function (o, k) { return o[k]; },
        keys = key.split(".");

    return array.sort(function (a, b) {
        return keys.reduce(getValue, a) - keys.reduce(getValue, b);
    });
}

var array = [{ a: 5, b: { c: 2 } }, { a: 7, b: { c: 1 } }, { a: 1, b: { c: 3 } }];



sortByKey(array, 'a');
console.log(array);
sortByKey(array, 'b.c');
console.log(array);

ES6

function sortByKey(array, key) {
    const getValue =
        (keys => object => keys.reduce((o, k) => o[k], object))
        (key.split('.'));

    return array.sort((a, b) => getValue(a) - getValue(b));
}

var array = [{ a: 5, b: { c: 2 } }, { a: 7, b: { c: 1 } }, { a: 1, b: { c: 3 } }];

sortByKey(array, 'a');
console.log(array);
sortByKey(array, 'b.c');
console.log(array);
.as-console-wrapper { max-height: 100% !important; top: 0; }

Comments

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.