5

I am using this function to sort an array based on object key:

function keysrt(arr, key, reverse) {
    var sortOrder = 1;
    if(reverse){
        sortOrder = -1;
    }
    return arr.sort(function(a, b) {
        var x = a[key],
            y = b[key];

        return sortOrder * ((x < y) ? -1 : ((x > y) ? 1 : 0));
    });
}   

It works well with this type of array, where key is on the first level:

var a = [ 
    { id: 0, last: 'Anne'},
    { id: 1, last: 'Odine'},
    { id: 2, last: 'Caroline'}
]

keysrt(a, 'last');

How can I make it work with this example, where title key is nested?

var b = [ 
    { id: 0, last: 'Anne',     data:{title: 'habc'}},
    { id: 1, last: 'Odine',    data:{title: 'asdf'}},
    { id: 2, last: 'Prentice', data:{title: 'tzuio'}}
]

keysrt(b, 'title');

5 Answers 5

9

For this idea the "key" variable changes into an array of keys: Then you specify the "path" to the nested value you want to sort on.

function keysrt(arr, keyArr, reverse) {
    var sortOrder = 1;
    if(reverse)sortOrder = -1;
    return arr.sort(function(a, b) {
        var x=a,y=b;
        for (var i=0; i < keyArr.length; i++) {
          x = x[keyArr[i]];
          y = y[keyArr[i]];
        }
        return sortOrder * ((x < y) ? -1 : ((x > y) ? 1 : 0));
    });
} 

keysrt(b,['data','title']);
Sign up to request clarification or add additional context in comments.

Comments

4

If you are ready to change the function signature and the function call, here is a simple solution-

function keysrt(arr, prop, key, reverse) {
    var sortOrder = 1;
    if(reverse)sortOrder = -1;
    return arr.sort(function(a, b) {
        var x = a[prop][key]; var y = b[prop][key];
        return sortOrder * ((x < y) ? -1 : ((x > y) ? 1 : 0));
    });
}   


var b = [ 
    { id: 0, last: 'Anne',     data:{title: 'habc'}},
    { id: 1, last: 'Odine',    data:{title: 'asdf'}},
    { id: 2, last: 'Prentice', data:{title: 'tzuio'}}
]

keysrt(b,'data', 'title');

Here, prop represents the outer object, key would represent the nested key.

So, var y = b[prop][key] would basically mean you are accessing b.data.title

Hope it helps :) Happy coding!

2 Comments

It's not "prototype"; perhaps you meant "signature". How would you extend this to handle keys at any level of nesting?
Sorry, edited the answer. Yes, I meant signature. And yeah, this is for one-level. For multi-level, we can extend the "prop" to be an array. or basically "James" solution looks pretty in that case! :)
2

If you need to make it generic, I think you can pass in a function that will retrieve the value from array item for comparison:

function keysrt(arr, reverse, getValueFn) {
    var sortOrder = 1;
    if(reverse)sortOrder = -1;
    return arr.sort(function(a, b) {
        var x = getValueFn(a); var y = getValueFn(b);
        return sortOrder * ((x < y) ? -1 : ((x > y) ? 1 : 0));
    });
}

So that you can use it like:

keysrt(b, true, function(a){return a.data.title})   

Comments

1

You can get working example with following code:

function keysrt(arr, key, reverse) {
    var sortOrder = reverse ? -1 : 1;

    return arr.sort(function(a, b) {
        var x,y;

        if(typeof a[key] !== "undefined") {
          x = a[key]; 
          y = b[key];
        } else {
          for(var prop in a) {
            if(a[prop][key] !== "undefined") {
              x = a[prop][key];
              y = b[prop][key];
            }
          }
        }

        return sortOrder * ((x < y) ? -1 : ((x > y) ? 1 : 0));
    });
}   

but I would propose more generic solution

function keysrt(arr, path, reverse) {
    var sortOrder = reverse ? -1 : 1;
    var pathSplitted = path.split(".");

    if(arr.length <= 1) {
      return arr;
    }

    return arr.sort(function(a, b) {
        var x = a;
        var y = b;

        pathSplitted.forEach(function(key) {
          x = x[key];
          y = y[key];
        });     

        return sortOrder * ((x < y) ? -1 : ((x > y) ? 1 : 0));
    });
}   

in which one can provide a path to sorting field like this

var sorted = keysrt(b, 'data.title');

Demo: http://jsbin.com/cosugawoga/edit?js,console

2 Comments

How does one specify to sort on the title element of data?
The same way that author provided in question keysrt(b, 'title');.
1

To find a nested property value, any number of levels down, you can use JSON.stringify as a way to walk the object:

function get_nested_value(obj, prop) {
  var result;
  JSON.stringify(obj, function(key, value) {
    if (key === prop) result = value;
  });
  return result;
}

Now:

function keysrt(arr, key, reverse) {
    var sortOrder = 1;
    if(reverse){
        sortOrder = -1;
    }
    return arr.sort(function(a, b) {
        var x = get_nested_value(a, key);
            y = get_nested_value(b, key);

        return sortOrder * ((x < y) ? -1 : ((x > y) ? 1 : 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.