按嵌套键对数组进行排序

5
我正在使用这个函数基于对象键来对数组进行排序:
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));
    });
}   

它适用于这种类型的数组,在这种数组中,键位于第一层:

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

keysrt(a, 'last');

如何使其与此示例一起使用,其中标题键是嵌套的?
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个回答

9
对于这个想法,"key"变量变成了一个键的数组:然后您可以指定要按其排序的嵌套值的"path"。
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']);

4
如果您准备好更改功能签名和调用,则有一个简单的解决方案——
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');

在这里,“prop”代表外部对象,“key”代表嵌套的键。 因此,“var y = b[prop][key]”基本上意味着您正在访问“b.data.title”。 希望它有所帮助 :) 开心编码!

这不是“原型”; 也许你的意思是“签名”。你如何扩展它以处理任何嵌套级别的键? - user663031
抱歉,我编辑了答案。是的,我指的是签名。对于单层级别,我们可以将“prop”扩展为数组。或者基本上,“James”的解决方案在那种情况下看起来很好! :) - bozzmob

2

如果你需要让它更通用化,我认为你可以传入一个函数来获取数组项的值进行比较:

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));
    });
}

这样你就可以像这样使用它:

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

1
您可以使用以下代码获取工作示例:
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));
    });
}   

但我会提出更通用的解决方案。
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));
    });
}   

其中可以提供类似以下的排序字段路径

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

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


如何指定按datatitle元素排序? - Scott Hunter
与作者在问题中提供的方式相同 keysrt(b, 'title'); - Mateusz Nowak

1
为了查找嵌套属性的值,无论有多少级别,您可以使用JSON.stringify作为遍历对象的一种方式:
function get_nested_value(obj, prop) {
  var result;
  JSON.stringify(obj, function(key, value) {
    if (key === prop) result = value;
  });
  return result;
}

现在:
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));
    });
}  

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接