问题描述
我有对象数组。它可以包含字符串和整数。我想根据属性对其进行排序,
在其中一个排序顺序(asc/desc)中,空值应该排在第一位。
当数组中不存在属性或为 null 时,应将其视为 null。就像在某些元素中未定义年龄或缺少姓氏
数组的例子是这个
function dynamicsort(property,order) {
var sort_order = 1;
if(order === "desc"){
sort_order = -1;
}
return function (a,b){
// a should come before b in the sorted order
if(a[property] < b[property]){
return -1 * sort_order;
// a should come after b in the sorted order
}else if(a[property] > b[property]){
return 1 * sort_order;
// a and b are the same
}else{
return 0 * sort_order;
}
}
}
let employees = [
{
firstName: 'John',age: 27,joinedDate: 'December 15,2017'
},{
firstName: 'Ana',lastName: 'Rosy',age: 25,joinedDate: 'January 15,2019'
},{
firstName: 'Zion',lastName: 'Albert',age: 30,joinedDate: 'February 15,2011'
},{
firstName: 'ben',lastName: 'Doe',{
firstName: 'Tom',];
console.log("Object to be sorted");
console.log(employees);
console.log("Sorting based on the age property")
console.log(employees.sort(dynamicsort("age","desc")));
console.log("Sorting based on the age property")
console.log(employees.sort(dynamicsort("age","asc")));
console.log("Sorting based on the lastName property")
console.log(employees.sort(dynamicsort("lastName","desc")));
console.log("Sorting based on the lastName property")
console.log(employees.sort(dynamicsort("lastName","asc")));
解决方法
您可以提前检查并将 undefined
或 null
值移到顶部。
function dynamicsort(property,order) {
const
isNullOrUndefined = v => v === undefined || v === null,sort_order = -(order === "desc") || 1;
return function(a,b) {
return sort_order * (
isNullOrUndefined(a[property]) - isNullOrUndefined(b[property])||
(a[property] > b[property]) - (a[property] < b[property])
);
}
}
const
employees = [{ firstName: 'John',age: 27,joinedDate: 'December 15,2017' },{ firstName: 'Ana',lastName: 'Rosy',age: 25,joinedDate: 'January 15,2019' },{ firstName: 'Zion',lastName: 'Albert',age: 30,joinedDate: 'February 15,2011' },{ firstName: 'ben',lastName: 'Doe',{ firstName: 'Tom',2017',age: null }];
console.log("Object to be sorted");
console.log(employees);
console.log("Sorting based on the age property desc")
console.log(employees.sort(dynamicsort("age","desc")));
console.log("Sorting based on the age property asc")
console.log(employees.sort(dynamicsort("age","asc")));
console.log("Sorting based on the lastName property desc")
console.log(employees.sort(dynamicsort("lastName","desc")));
console.log("Sorting based on the lastName property asc")
console.log(employees.sort(dynamicsort("lastName","asc")));
.as-console-wrapper { max-height: 100% !important; top: 0; }
一种简单的方法是在比较之前检查两个元素之一是否未定义。
您可以使用前两次比较的返回值,最终删除乘以 sort_order
并决定是否希望缺失的字段始终位于顶部或始终位于底部。
function dynamicsort(property,order) {
var sort_order = 1;
if(order === "desc"){
sort_order = -1;
}
return function (a,b){
//check if one of the property is undefined
if(a[property] == null){
return 1 * sort_order;
}
if(b[property] == null){
return -1 * sort_order;
}
// if we are working with strings,we can perform case-insensitive comparison
if((typeof a[property] === 'string') && (typeof b[property] === 'string')){
return sort_order * a[property].localeCompare(b[property],'en',{'sensitivity': 'base'});
}
// a should come before b in the sorted order
if(a[property] < b[property]){
return -1 * sort_order;
// a should come after b in the sorted order
}else if(a[property] > b[property]){
return 1 * sort_order;
// a and b are the same
}else{
return 0 * sort_order;
}
}
}
let employees = [
{
firstName: 'John',2017'
},{
firstName: 'Ana',2019'
},{
firstName: 'Zion',2011'
},{
firstName: 'ben',{
firstName: 'Tom',];
console.log("Object to be sorted");
console.log(employees);
console.log("Sorting based on the age property")
console.log(employees.sort(dynamicsort("age","desc")));
console.log("Sorting based on the age property")
console.log(employees.sort(dynamicsort("age","asc")));
console.log("Sorting based on the lastName property")
console.log(employees.sort(dynamicsort("lastName","desc")));
console.log("Sorting based on the lastName property")
console.log(employees.sort(dynamicsort("lastName","asc")));
另外,如果你像我一样喜欢单行条件,并且你不关心排序不稳定(即交换具有相同属性的项目),你可以将返回函数写为:
/* does not perform case-insensitive comparison on strings */
return sort_order * (a[property] == null ? 1 : (b[property] == null ? -1 : (a[property] < b[property] ? -1 : 1)))
虽然可读性会差一点?
,我会这样做:(在 Nullish coalescing operator (??) 的帮助下)
little extra:这种排序自动支持数据类型:数字、字符串和表示日期的字符串。
(对于布尔值:true = 1 和 false = 0)
function dynamicsort( property,order='asc' )
{
let sortOrder = (order === 'desc') ? -1 : 1
return function(a_Obj,b_Obj)
{
let a = a_Obj[property] ?? null,b = b_Obj[property] ?? null
;
if (a===null || b===null) return (a===b)? 0 : (a===null)? -1 : +1
if (!isNaN(a)) return (a - b) * sortOrder
if (isNaN(Date.parse(a))) return (a.localeCompare(b)) * sortOrder
return (Date.parse(a) - Date.parse(b)) * sortOrder
}
}
const employees =
[ { firstName: 'John',2019' },2017' }
]
let verif = ''
verif = 'sort -> firstName asc\n'
employees
.sort(dynamicsort('firstName','asc'))
.forEach(o=> verif += JSON.stringify(o) + '\n' )
console.log( verif )
verif = 'sort -> firstName desc\n'
employees
.sort(dynamicsort('firstName','desc'))
.forEach(o=> verif += JSON.stringify(o) + '\n' )
console.log( verif )
verif = 'sort -> lastName asc\n'
employees
.sort(dynamicsort('lastName','asc'))
.forEach(o=> verif += JSON.stringify(o) + '\n' )
console.log( verif )
verif = 'sort -> lastName desc\n'
employees
.sort(dynamicsort('lastName','desc'))
.forEach(o=> verif += JSON.stringify(o) + '\n' )
console.log( verif )
verif = 'sort -> age asc\n'
employees
.sort(dynamicsort('age','asc'))
.forEach(o=> verif += JSON.stringify(o) + '\n' )
console.log( verif )
verif = 'sort -> age desc\n'
employees
.sort(dynamicsort('age','desc'))
.forEach(o=> verif += JSON.stringify(o) + '\n' )
console.log( verif )
verif = 'sort -> joinedDate asc\n'
employees
.sort(dynamicsort('joinedDate','asc'))
.forEach(o=> verif += JSON.stringify(o) + '\n' )
console.log( verif )
verif = 'sort -> joinedDate desc\n'
employees
.sort(dynamicsort('joinedDate','desc'))
.forEach(o=> verif += JSON.stringify(o) + '\n' )
console.log( verif )
.as-console-wrapper {max-height: 100%!important;top:0}