对象的Javascript动态排序数组在排序时包含空值

问题描述

我有对象数组。它可以包含字符串和整数。我想根据属性对其进行排序,

在其中一个排序顺序(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")));

解决方法

您可以提前检查并将 undefinednull 值移到顶部。

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}