按多个属性对对象数组进行排序

3

我有一个像这样的对象数组:

var a = [
    { id: 1, score: 1, isCut: false, dnf: false },
    { id: 2, score: 2, isCut: false, dnf: false },
    { id: 3, score: 3, isCut: false, dnf: false },
    { id: 4, score: 4, isCut: false, dnf: false },
    { id: 5, score: 5, isCut: true, dnf: true },
    { id: 6, score: 6, isCut: true, dnf: false },
    { id: 7, score: 7, isCut: true, dnf: false },
    { id: 8, score: 8, isCut: true, dnf: false },
    { id: 9, score: 9, isCut: true, dnf: false },
    { id: 10, score: 0, isCut: false, dnf: false },
    { id: 11, score: -1, isCut: false, dnf: false },
    { id: 12, score: -2, isCut: false, dnf: true },
    { id: 13, score: -3, isCut: false, dnf: false },
    { id: 14, score: -4, isCut: false, dnf: false },
    { id: 15, score: -5, isCut: false, dnf: false },
    { id: 16, score: 10, isCut: true, dnf: false }
];

我需要按照以下标准对数组进行分组和排序:

  1. 如果dnf是真的,对象就会被放在底部; 所有dnf对象应该按分数排序
  2. 如果isCut是真的,对象就会被放在底部,但在dnf之上; 所有isCut对象应该按分数排序
  3. 其余部分应按score排序,如果分数相等,则按id排序

5
Array.sort 接受一个比较函数。 - Benjamin Gruenbaum
1
是的,但如何实现它,这才是问题。 - Gerstmann
2
看这个链接,希望能对你有所帮助 :) - Michael Unterthurner
3个回答

12

(更新) 这是你在评论中提到的问题的答案。

a.sort(function(a, b) {
  if (a.dnf != b.dnf) {
    return a.dnf ? 1 : -1;
  }
  if (!(a.dnf && b.dnf) && a.isCut != b.isCut) {
    return a.isCut ? 1 : -1;
  }
  if (a.score != b.score) {
    return b.score - a.score; // descending
  }
  return b.id - a.id; // descending
});

结果:

[
  {"id":4,"score":4,"isCut":false,"dnf":false},   // the rest: order by score, id
  {"id":3,"score":3,"isCut":false,"dnf":false},   //
  {"id":2,"score":2,"isCut":false,"dnf":false},   //
  {"id":1,"score":1,"isCut":false,"dnf":false},   //
  {"id":10,"score":0,"isCut":false,"dnf":false},  //
  {"id":11,"score":-1,"isCut":false,"dnf":false}, //
  {"id":13,"score":-3,"isCut":false,"dnf":false}, //
  {"id":14,"score":-4,"isCut":false,"dnf":false}, //
  {"id":15,"score":-5,"isCut":false,"dnf":false}, //
  {"id":16,"score":10,"isCut":true,"dnf":false}, // isCut: order by score, id
  {"id":9,"score":9,"isCut":true,"dnf":false},   //
  {"id":8,"score":8,"isCut":true,"dnf":false},   //
  {"id":7,"score":7,"isCut":true,"dnf":false},   //
  {"id":6,"score":6,"isCut":true,"dnf":false},   //
  {"id":5,"score":5,"isCut":true,"dnf":true},   // dnf: order by score, id
  {"id":12,"score":-2,"isCut":false,"dnf":true} //
]

1
这是首先按dnf排序。 isCut将不会被准确排序。您首先想要所有isCut为true的项目,然后是isCut为false的项目。 - Amberlamps
@amberlamps 我不理解。OP难道不想把“dnf”对象放在底部吗?那么我们应该先按“dnf”排序。 - Mics
你理解得没错,但他想要在那之上加一个 isCut 如果它是 true。所以它可以按照 true/truetrue/falsefalse/true 的顺序来展示。 - Amberlamps
你必须使用大量不同的数据进行测试才能确保它的正确性,但目前看起来非常好。+1 - Amberlamps

0
这是一种不同的方法,它使用一个数组来进行排序,这个数组的顺序是不规则的,如果只考虑dnfisCut属性而不看两者,则无法实现想要的排序。如果我们将这两个值放入真值表中,那么排序顺序就无法反映所需的顺序。
                   2*dnf+isCut
    dnf     isCut     value     order
--------  --------  --------  --------
     0         0         0         0
     0         1         1         1
     1         1         3         2
     1         0         2         3
为了纠正排序顺序,我建议使用数组以获得正确的顺序。

var data = [{ id: 1, score: 1, isCut: false, dnf: false }, { id: 2, score: 2, isCut: false, dnf: false }, { id: 3, score: 3, isCut: false, dnf: false }, { id: 4, score: 4, isCut: false, dnf: false }, { id: 5, score: 5, isCut: true, dnf: true }, { id: 6, score: 6, isCut: true, dnf: false }, { id: 7, score: 7, isCut: true, dnf: false }, { id: 8, score: 8, isCut: true, dnf: false }, { id: 9, score: 9, isCut: true, dnf: false }, { id: 10, score: 0, isCut: false, dnf: false }, { id: 11, score: -1, isCut: false, dnf: false }, { id: 12, score: -2, isCut: false, dnf: true }, { id: 13, score: -3, isCut: false, dnf: false }, { id: 14, score: -4, isCut: false, dnf: false }, { id: 15, score: -5, isCut: false, dnf: false }, { id: 16, score: 10, isCut: true, dnf: false }];

data.sort(function (a, b) {
    function order(dnf, isCut) { return [0, 1, 3, 2][dnf * 2 + isCut]; }

    return order(a.dnf, a.isCut) - order(b.dnf, b.isCut) || b.score - a.score;
});

console.log(data);
.as-console-wrapper { max-height: 100% !important; top: 0; }


-1

这仅适用于字符串。作者有多种类型需要处理。 - Delice

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