Sắp xếp (thêm) Mảng phức tạp của các đối tượng
Vì bạn có thể gặp các cấu trúc dữ liệu phức tạp hơn như mảng này, tôi sẽ mở rộng giải pháp.
TL; DR
Là phiên bản dễ cắm hơn dựa trên câu trả lời rất đáng yêu của @ ege-Özcan .
Vấn đề
Tôi đã gặp những điều dưới đây và không thể thay đổi nó. Tôi cũng không muốn làm phẳng đối tượng tạm thời. Tôi cũng không muốn sử dụng dấu gạch dưới / lodash, chủ yếu là vì lý do hiệu suất và niềm vui để tự thực hiện nó.
var People = [
{Name: {name: "Name", surname: "Surname"}, Middlename: "JJ"},
{Name: {name: "AAA", surname: "ZZZ"}, Middlename:"Abrams"},
{Name: {name: "Name", surname: "AAA"}, Middlename: "Wars"}
];
Mục tiêu
Mục tiêu là sắp xếp nó chủ yếu theo People.Name.name
và thứ hai bởiPeople.Name.surname
Chướng ngại vật
Bây giờ, trong giải pháp cơ sở sử dụng ký hiệu khung để tính toán các thuộc tính để sắp xếp động. Tuy nhiên, ở đây, chúng ta sẽ phải xây dựng ký hiệu khung một cách linh hoạt, vì bạn sẽ mong đợi một số nhưPeople['Name.name']
sẽ hoạt động - điều này không có.
People['Name']['name']
Mặt khác, chỉ đơn giản là làm tĩnh và chỉ cho phép bạn đi xuống n cấp thứ .
Giải pháp
Bổ sung chính ở đây sẽ là đi xuống cây đối tượng và xác định giá trị của lá cuối cùng, bạn phải chỉ định, cũng như bất kỳ lá trung gian nào.
var People = [
{Name: {name: "Name", surname: "Surname"}, Middlename: "JJ"},
{Name: {name: "AAA", surname: "ZZZ"}, Middlename:"Abrams"},
{Name: {name: "Name", surname: "AAA"}, Middlename: "Wars"}
];
People.sort(dynamicMultiSort(['Name','name'], ['Name', '-surname']));
// Results in...
// [ { Name: { name: 'AAA', surname: 'ZZZ' }, Middlename: 'Abrams' },
// { Name: { name: 'Name', surname: 'Surname' }, Middlename: 'JJ' },
// { Name: { name: 'Name', surname: 'AAA' }, Middlename: 'Wars' } ]
// same logic as above, but strong deviation for dynamic properties
function dynamicSort(properties) {
var sortOrder = 1;
// determine sort order by checking sign of last element of array
if(properties[properties.length - 1][0] === "-") {
sortOrder = -1;
// Chop off sign
properties[properties.length - 1] = properties[properties.length - 1].substr(1);
}
return function (a,b) {
propertyOfA = recurseObjProp(a, properties)
propertyOfB = recurseObjProp(b, properties)
var result = (propertyOfA < propertyOfB) ? -1 : (propertyOfA > propertyOfB) ? 1 : 0;
return result * sortOrder;
};
}
/**
* Takes an object and recurses down the tree to a target leaf and returns it value
* @param {Object} root - Object to be traversed.
* @param {Array} leafs - Array of downwards traversal. To access the value: {parent:{ child: 'value'}} -> ['parent','child']
* @param {Number} index - Must not be set, since it is implicit.
* @return {String|Number} The property, which is to be compared by sort.
*/
function recurseObjProp(root, leafs, index) {
index ? index : index = 0
var upper = root
// walk down one level
lower = upper[leafs[index]]
// Check if last leaf has been hit by having gone one step too far.
// If so, return result from last step.
if (!lower) {
return upper
}
// Else: recurse!
index++
// HINT: Bug was here, for not explicitly returning function
// https://stackoverflow.com/a/17528613/3580261
return recurseObjProp(lower, leafs, index)
}
/**
* Multi-sort your array by a set of properties
* @param {...Array} Arrays to access values in the form of: {parent:{ child: 'value'}} -> ['parent','child']
* @return {Number} Number - number for sort algorithm
*/
function dynamicMultiSort() {
var args = Array.prototype.slice.call(arguments); // slight deviation to base
return function (a, b) {
var i = 0, result = 0, numberOfProperties = args.length;
// REVIEW: slightly verbose; maybe no way around because of `.sort`-'s nature
// Consider: `.forEach()`
while(result === 0 && i < numberOfProperties) {
result = dynamicSort(args[i])(a, b);
i++;
}
return result;
}
}
Thí dụ
Ví dụ hoạt động trên JSBin