Sorting an array on a nested key

I use this function to sort an array based on an 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));
    });
}   

This works well with an array of this type, where the 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 the header 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');
+4
source share
5 answers

For this idea, the variable "key" is changed to an array of keys: Then you specify the "path" to the nested value that you want to sort.

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']);
+6
source

If you are ready to change the function signature and 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 proprepresents an external object, keywill represent a nested key.

, var y = b[prop][key] , b.data.title

, :) !

+3

, , , :

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 you can use it, for example:

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

To find the value of a nested property, any number of levels down, you can use JSON.stringifyas a way to move 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));
    });
}  
+1
source

You can get a working example with the 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 suggest a more general 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));
    });
}   

where you can specify a path to a sort field like this

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

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

0
source

Source: https://habr.com/ru/post/1623459/


All Articles