JavaScript数组按多个值(字符串和数字)排序

5
我希望对一个数组按照 科目 (字符串、按字母顺序),然后是 水平 (整数、升序),最后是 名称 (字符串、按字母顺序) 进行排序。我在 Stack Overflow 上找到了许多其他的线程,但没有发现按多个变量类型排序的线程。我以为我已经做到了,但它并未正确排序。

排序功能:

scipads.sort(function (a, b) {
    if (a.subject != b.subject)
        return a.subject < b.subject;
    if (a.level != b.level)
        return a.level - b.level;
    return a.name < b.name;
});

数组:

var scipads = [{
        "name": "L2 Physics Externals",
        "level": 2,
        "subject": "physics",
    }, {
        "name": "L2 Physics Internals",
        "level": 2,
        "subject": "physics",
    }, {
        "name": "L2 Chem Externals",
        "level": 2,
        "subject": "chemistry",
    }, {
        "name": "L2 Chem Internals",
        "level": 2,
        "subject": "chemistry",
    }, {
        "name": "L2 Bio Internals",
        "level": 2,
        "subject": "biology",
    }, {
        "name": "L2 Bio Externals",
        "level": 2,
        "subject": "biology",
    }, {
        "name": "L1 Electricity & Magnetism",
        "level": 1,
        "subject": "physics",
    }, {
        "name": "L1 Wave Behaviour",
        "level": 1,
        "subject": "physics",
    }, {
        "name": "L1 Heat",
        "level": 1,
        "subject": "physics",
    }, {
        "name": "L1 Carbon Chemistry",
        "level": 1,
        "subject": "chemistry",
    }, {
        "name": "L1 Selected Elements",
        "level": 1,
        "subject": "chemistry",
    }, {
        "name": "L1 Chemical Reactions",
        "level": 1,
        "subject": "chemistry",
    },
];

我该如何按主题、水平和姓名进行排序?

也许可以先按主题排序,然后将所有具有相同主题的项目放入新列表中并按级别排序,接着按名称进行相同操作,最后将它们拼接在一起? - xDreamCoding
字符串需要使用a.subject.localeCompare(b.subject)进行比较。排序函数需要返回正数、负数或零。目前对于字符串只返回truefalse,表示正数和零,缺少负数的情况。 - Sebastian Simon
那么如果它是假的,应该返回“-1”吗? - DarkMatterMatt
2
@DarkMatterMatt 当第一个值需要在第二个值之前出现时,它需要返回“-1”。 - Sebastian Simon
你可以把所有东西简化成 scipads.sort((a, b) => a.subject.localeCompare(b.subject) || a.level - b.level || a.name.localeCompare(b.name)); - Sebastian Simon
是的,但性能不是首要考虑因素,而且对于我这样的初学者来说,用if else方式阅读更短的代码行更容易。有关使用||的说明和示例,请访问https://dev59.com/cm455IYBdhLWcg3wCPjh#27993435。 - DarkMatterMatt
5个回答

3

使用localeCompare进行字符串比较

var scipads=[{name:"L2 Physics Externals",level:2,subject:"physics"},{name:"L2 Physics Internals",level:2,subject:"physics"},{name:"L2 Chem Externals",level:2,subject:"chemistry"},{name:"L2 Chem Internals",level:2,subject:"chemistry"},{name:"L2 Bio Internals",level:2,subject:"biology"},{name:"L2 Bio Externals",level:2,subject:"biology"},{name:"L1 Electricity & Magnetism",level:1,subject:"physics"},{name:"L1 Wave Behaviour",level:1,subject:"physics"},{name:"L1 Heat",level:1,subject:"physics"},{name:"L1 Carbon Chemistry",level:1,subject:"chemistry"},{name:"L1 Selected Elements",level:1,subject:"chemistry"},{name:"L1 Chemical Reactions",level:1,subject:"chemistry"}];

scipads.sort(function(a, b) {
  if (a.subject != b.subject)
    return a.subject.localeCompare(b.subject);
  else if (a.level != b.level)
    return a.level - b.level;
  return a.name.localeCompare(b.name);
});

console.log(scipads);


因为正确处理了大写字母(并以正确的方式进行排序),所以我接受了你的答案。 - DarkMatterMatt
谢谢,localeCompare 对于非英语字符也很有用。 - A. L

2
比较应该返回一个整数。这里有一个例子:
scipads.sort((a, b) => {
    if (a.subject != b.subject) { 
        return a.subject < b.subject ? -1 : 1; 
    }
    if (a.level != b.level) { 
        return a.level - b.level; 
    }
    return a.name < b.name ? -1 : 1;
})

嘿,不错的箭头运算符。每天都能学到新东西。 - DarkMatterMatt
1
@DarkMatterMatt 箭头操作符是 ES6 中引入的一种名为“箭头函数”的特性。 - Sash Sinha
仅为了正确性,请将 < 更改为 >。它正在进行 Z-A 排序。 - DarkMatterMatt
@DarkMatterMatt,你能再确认一下吗?在我的端上排序是正确的 :) - Andy Gaskell
哈哈,是我错了,我一直以为是 ? 1 : -1; 而不是相反的。抱歉 :P - DarkMatterMatt

1
你的排序比较函数接近正确,但还不够完美。应该返回-1表示小于,0表示相等,1表示大于。请参考这里中的文档。
例如:将return a.subject < b.subject 改为 return a.subject < b.subject ? -1 : 1;

谢谢,我刚刚自己也找到了 :P (感谢 Xufox)。我可以在5分钟内接受这个答案。 - DarkMatterMatt
很高兴它来到了你这里! - pacifier21

0

我的解决方案是先比较主题,然后再比较级别。

var scipads=[{name:"L2 Physics Externals",level:2,subject:"physics"},{name:"L2 Physics Internals",level:2,subject:"physics"},{name:"L2 Chem Externals",level:2,subject:"chemistry"},{name:"L2 Chem Internals",level:2,subject:"chemistry"},{name:"L2 Bio Internals",level:2,subject:"biology"},{name:"L2 Bio Externals",level:2,subject:"biology"},{name:"L1 Electricity & Magnetism",level:1,subject:"physics"},{name:"L1 Wave Behaviour",level:1,subject:"physics"},{name:"L1 Heat",level:1,subject:"physics"},{name:"L1 Carbon Chemistry",level:1,subject:"chemistry"},{name:"L1 Selected Elements",level:1,subject:"chemistry"},{name:"L1 Chemical Reactions",level:1,subject:"chemistry"}];

// sort by subject, then level, then name
var res = scipads.sort((a, b) => {
  if (a.subject > b.subject) {
    return 1;
  } else if (a.subject < b.subject) {
    return -1;
  } else if ( a.level > b.level){
    return 1;
  } else if (a.level < b.level) {
    return -1;
  } else if (a.name > b.name) {
    return 1;
  } else if (a.name < b.name) {
    return -1;
  }
  return 0;
});


console.log(res)


0

如果要比较字符串,应该使用 string.localeCompare。此外,您可以尝试创建一个带有优先级列表的数组,并循环遍历它以进行排序。

var scipads=[{name:"L2 Physics Externals",level:2,subject:"physics"},{name:"L2 Physics Internals",level:2,subject:"physics"},{name:"L2 Chem Externals",level:2,subject:"chemistry"},{name:"L2 Chem Internals",level:2,subject:"chemistry"},{name:"L2 Bio Internals",level:2,subject:"biology"},{name:"L2 Bio Externals",level:2,subject:"biology"},{name:"L1 Electricity & Magnetism",level:1,subject:"physics"},{name:"L1 Wave Behaviour",level:1,subject:"physics"},{name:"L1 Heat",level:1,subject:"physics"},{name:"L1 Carbon Chemistry",level:1,subject:"chemistry"},{name:"L1 Selected Elements",level:1,subject:"chemistry"},{name:"L1 Chemical Reactions",level:1,subject:"chemistry"}];

var priority = ["subject", "level", "name"]

scipads.sort(function(a,b){
  var val = 0;
  priority.some(function(k){
    val = compare(a,b,k);
    return val !== 0;
  });
})

function compare(a,b,k){
  switch(typeof a[k]){
    case "string": return a[k].localeCompare(b[k]);
    case "number": return a[k] - b[k]
  }
}

console.log(scipads)


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