如何按多个字段对对象数组进行排序?

374

从这个原始问题中,我该如何对多个字段进行排序?

使用这个稍微调整过的结构,我该如何对城市(升序)和价格(降序)进行排序?

var homes = [
    {"h_id":"3",
     "city":"Dallas",
     "state":"TX",
     "zip":"75201",
     "price":"162500"},
    {"h_id":"4",
     "city":"Bevery Hills",
     "state":"CA",
     "zip":"90210",
     "price":"319250"},
    {"h_id":"6",
     "city":"Dallas",
     "state":"TX",
     "zip":"75000",
     "price":"556699"},
    {"h_id":"5",
     "city":"New York",
     "state":"NY",
     "zip":"00010",
     "price":"962500"}
    ];

我喜欢这个答案提供了一个通用的方法。在我计划使用这段代码的地方,我需要对日期以及其他事物进行排序。如果不考虑有些繁琐,预处理对象的能力似乎很方便。

我尝试将这个答案构建成一个好的通用示例,但是我没有太多的成功。


你想搜索还是排序? - Felix Kling
你使用你链接的第二个答案时遇到了什么问题? - canon
它不够通用。我似乎在添加大量代码,而我只想说sort(["first-field", "ASC"], ["second-field", "DSC"]);。当我尝试添加第一个答案的“primer”逻辑以处理日期、大小写不敏感等时,这变得更加复杂。 - Mike
4
如果你愿意使用lodash,可以查看https://lodash.com/docs/4.17.11#orderBy。 - Deepanshu Arora
按属性排序的模式是 homes.sort((a, b) =>),其中 a.propb.propa.prop - b.prop 数值排序,a.prop.localeCompare(b.prop) 字典序排序,(b.prop < a.prop) - (a.prop < b.prop) 通用排序。要按降序排序而不是升序,请取反返回值(例如,使用 b.prop - a.prop 而不是 a.prop - b.prop)。 - Sebastian Simon
42个回答

0

// Array of objects representing the data
const data = [
  { name: 'John', surname: 'Doe', birthdate: new Date(1980, 5, 15) },
  { name: 'Jane', surname: 'Smith', birthdate: new Date(1990, 2, 28) },
  { name: 'Alex', surname: 'Johnson', birthdate: new Date(1985, 8, 10) },
  // Additional objects...
];

// Custom comparator function for multiple field sorting
function multiFieldSort(a, b) {
  // Sorting fields and orders
  const fields = [
    { name: 'name', order: 'asc' },
    { name: 'surname', order: 'desc' },
    { name: 'birthdate', order: 'desc' },
  ];

  // Iterate over fields and perform comparisons
  for (const field of fields) {
    const aValue = a[field.name];
    const bValue = b[field.name];

    let comparison = 0;

    if (typeof aValue === 'string' && typeof bValue === 'string') {
      comparison = aValue.localeCompare(bValue);
    } else if (typeof aValue === 'number' && typeof bValue === 'number') {
      comparison = aValue - bValue;
    } else if (aValue instanceof Date && bValue instanceof Date) {
      comparison = aValue.getTime() - bValue.getTime();
    }

    if (comparison !== 0) {
      return field.order === 'asc' ? comparison : -comparison;
    }
  }

  // Default case: preserve the original order
  return 0;
}

// Sort the data array using the multiFieldSort function
data.sort(multiFieldSort);

// Output the sorted data
console.log(data);


0

这里的'AffiliateDueDate'和'Title'都是列名,它们按升序排序。

array.sort(function(a, b) {

               if (a.AffiliateDueDate > b.AffiliateDueDate ) return 1;
               else if (a.AffiliateDueDate < b.AffiliateDueDate ) return -1;
               else if (a.Title > b.Title ) return 1;
               else if (a.Title < b.Title ) return -1;
               else return 0;
             })

0

哇,这里有一些复杂的解决方案。它们如此复杂,以至于我决定提出一个更简单但同样强大的解决方案。在这里:

function sortByPriority(data, priorities) {
  if (priorities.length == 0) {
    return data;
  }

  const nextPriority = priorities[0];
  const remainingPriorities = priorities.slice(1);

  const matched = data.filter(item => item.hasOwnProperty(nextPriority));
  const remainingData = data.filter(item => !item.hasOwnProperty(nextPriority));

  return sortByPriority(matched, remainingPriorities)
    .sort((a, b) => (a[nextPriority] > b[nextPriority]) ? 1 : -1)
    .concat(sortByPriority(remainingData, remainingPriorities));
}

这里是如何使用它的示例。

const data = [
  { id: 1,                         mediumPriority: 'bbb', lowestPriority: 'ggg' },
  { id: 2, highestPriority: 'bbb', mediumPriority: 'ccc', lowestPriority: 'ggg' },
  { id: 3,                         mediumPriority: 'aaa', lowestPriority: 'ggg' },
];

const priorities = [
  'highestPriority',
  'mediumPriority',
  'lowestPriority'
];


const sorted = sortByPriority(data, priorities);

这将首先按属性的优先级排序,然后按属性的值排序。


0
function sortMultiFields(prop){
    return function(a,b){
        for(i=0;i<prop.length;i++)
        {
            var reg = /^\d+$/;
            var x=1;
            var field1=prop[i];
            if(prop[i].indexOf("-")==0)
            {
                field1=prop[i].substr(1,prop[i].length);
                x=-x;
            }

            if(reg.test(a[field1]))
            {
                a[field1]=parseFloat(a[field1]);
                b[field1]=parseFloat(b[field1]);
            }
            if( a[field1] > b[field1])
                return x;
            else if(a[field1] < b[field1])
                return -x;
        }
    }
}

如何使用(如果您想按特定字段降序排序,请在字段前加上“-”符号)

homes.sort(sortMultiFields(["city","-price"]));

使用上述函数,您可以对具有多个字段的任何JSON数组进行排序。无需改变函数主体。

0
这是一个递归算法,可以按多个字段排序,并在比较之前有机会格式化值。
var data = [
{
    "id": 1,
    "ship": null,
    "product": "Orange",
    "quantity": 7,
    "price": 92.08,
    "discount": 0
},
{
    "id": 2,
    "ship": "2017-06-14T23:00:00.000Z".toDate(),
    "product": "Apple",
    "quantity": 22,
    "price": 184.16,
    "discount": 0
},
...
]
var sorts = ["product", "quantity", "ship"]

// comp_val formats values and protects against comparing nulls/undefines
// type() just returns the variable constructor
// String.lower just converts the string to lowercase.
// String.toDate custom fn to convert strings to Date
function comp_val(value){
    if (value==null || value==undefined) return null
    var cls = type(value)
    switch (cls){
        case String:
            return value.lower()
    }
    return value
}

function compare(a, b, i){
    i = i || 0
    var prop = sorts[i]
    var va = comp_val(a[prop])
    var vb = comp_val(b[prop])

    // handle what to do when both or any values are null
    if (va == null || vb == null) return true

    if ((i < sorts.length-1) && (va == vb)) {
        return compare(a, b, i+1)
    } 
    return va > vb
}

var d = data.sort(compare);
console.log(d);

如果a和b相等,它将尝试下一个字段,直到没有可用的为止。

0

我认为这可能是最简单的方法。

https://coderwall.com/p/ebqhca/javascript-sort-by-two-fields

这非常简单,我尝试了三个不同的键值对,效果非常好。

这里有一个简单的例子,查看链接获取更多细节。

testSort(data) {
    return data.sort(
        a['nameOne'] > b['nameOne'] ? 1
        : b['nameOne'] > a['nameOne'] ? -1 : 0 ||
        a['date'] > b['date'] ||
        a['number'] - b['number']
    );
}

0
我在寻找类似的东西,最终得到了这个:
首先,我们有一个或多个排序函数,始终返回0、1或-1:
const sortByTitle = (a, b): number => 
  a.title === b.title ? 0 : a.title > b.title ? 1 : -1;

您可以为想要排序的每个其他属性创建更多函数。

然后我有一个将这些排序函数组合成一个的函数:

const createSorter = (...sorters) => (a, b) =>
  sorters.reduce(
    (d, fn) => (d === 0 ? fn(a, b) : d),
    0
  );

可以使用以下代码将上述排序函数以可读的方式组合起来:

const sorter = createSorter(sortByTitle, sortByYear)

items.sort(sorter)

当排序函数返回0时,下一个排序函数将被调用以进行进一步的排序。

0

以下是我的样例供您参考:

function msort(arr, ...compFns) {
  let fn = compFns[0];
  arr = [].concat(arr);
  let arr1 = [];
  while (arr.length > 0) {
    let arr2 = arr.splice(0, 1);
    for (let i = arr.length; i > 0;) {
      if (fn(arr2[0], arr[--i]) === 0) {
        arr2 = arr2.concat(arr.splice(i, 1));
      }
    }
    arr1.push(arr2);
  }

  arr1.sort(function (a, b) {
    return fn(a[0], b[0]);
  });

  compFns = compFns.slice(1);
  let res = [];
  arr1.map(a1 => {
    if (compFns.length > 0) a1 = msort(a1, ...compFns);
    a1.map(a2 => res.push(a2));
  });
  return res;
}

let tstArr = [{ id: 1, sex: 'o' }, { id: 2, sex: 'm' }, { id: 3, sex: 'm' }, { id: 4, sex: 'f' }, { id: 5, sex: 'm' }, { id: 6, sex: 'o' }, { id: 7, sex: 'f' }];

function tstFn1(a, b) {
  if (a.sex > b.sex) return 1;
  else if (a.sex < b.sex) return -1;
  return 0;
}

function tstFn2(a, b) {
  if (a.id > b.id) return -1;
  else if (a.id < b.id) return 1;
  return 0;
}

console.log(JSON.stringify(msort(tstArr, tstFn1, tstFn2)));
//output:
//[{"id":7,"sex":"f"},{"id":4,"sex":"f"},{"id":5,"sex":"m"},{"id":3,"sex":"m"},{"id":2,"sex":"m"},{"id":6,"sex":"o"},{"id":1,"sex":"o"}]

-1
这个简单的解决方案怎么样:
const sortCompareByCityPrice = (a, b) => {
    let comparison = 0
    // sort by first criteria
    if (a.city > b.city) {
        comparison = 1
    }
    else if (a.city < b.city) {
        comparison = -1
    }
    // If still 0 then sort by second criteria descending
    if (comparison === 0) {
        if (parseInt(a.price) > parseInt(b.price)) {
            comparison = -1
        }
        else if (parseInt(a.price) < parseInt(b.price)) {
            comparison = 1
        }
    }
    return comparison 
}

基于这个问题 按多个(数字)字段对JavaScript数组进行排序


-1

按照两个日期字段和一个数字字段进行排序的示例:

var generic_date =  new Date(2070, 1, 1);
checkDate = function(date) {
  return Date.parse(date) ? new Date(date): generic_date;
}

function sortData() {  
  data.sort(function(a,b){
    var deltaEnd = checkDate(b.end) - checkDate(a.end);
    if(deltaEnd) return deltaEnd;

    var deltaRank = a.rank - b.rank;
    if (deltaRank) return deltaRank;

    var deltaStart = checkDate(b.start) - checkDate(a.start);
    if(deltaStart) return deltaStart;

    return 0;
  });
}

http://jsfiddle.net/hcWgf/57/


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