JavaScript如何按照布尔属性对对象数组进行排序

164

请看结尾处的编辑以了解实际问题。

好的,我有一个场景:

a = [false, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, false, true, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false]

那么如果我这样做:

a.sort(function(a,b){return !a && b});

它给了我这个:

[false, false, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, false, true, false, false, false, false, false, false, true, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false]

有点像排序...但又不完全一样... :(

我该怎么对这个数组进行排序?

编辑:

如果你想知道为什么我没有使用a.sort(),是因为我的实际数组是对象数组,而不是像我发帖时那样的普通数组。实际数组的元素看起来像 [{xx:true},{xx:false},...]


如果我执行a.map(function(x){ return x?1:0 }).sort(function(a,b){return a>b});同样不起作用... 我觉得我可能做了一些基本错误的事情 - PCoelho
为什么需要编写自定义函数?a.sort() 应该可以工作。 - Haseeb Asif
1
有没有一种使用lodash的方法? - Mina Fawzy
15个回答

338

a = [false, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, false, true, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false];
    
    
    a.sort(function(x, y) {
        // true values first
        return (x === y)? 0 : x? -1 : 1;
        // false values first
        // return (x === y)? 0 : x? 1 : -1;
    });
    
    console.log(a);

当a和b的值相同时,您必须返回0;如果a为真,则返回-1,否则返回1。


65
更简洁的写法:a.sort((x, y) => y - x); - Joe Frambach
2
@PCoelho,考虑使用Joe的解决方案。它有效且更简洁。 - c.P.u1
4
@JoeFrambach,你能解释一下那是如何工作的,或者指向一个解释类似语法的主题吗? - Adam Moisa
14
乔的解决方案之所以有效,是因为有一种叫做类型转换的东西。基本上,JS引擎会注意到你在尝试对“布尔”值进行数学操作(减法),所以它会将“false”转换为“0”,将“true”转换为“1”。 - Silvestre Herrera
1
@SilvestreHerrera,以上示例中没有类型强制转换。根据文档 https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort,compareFunction 需要返回-1、0或1,这将确定元素的位置。上面的代码示例使用了嵌套的三元语句,在未注释的“真值优先”示例中,如果x和y严格相等,则返回0;否则,如果x为true,则返回-1,否则返回1。 - technicolorenvy
显示剩余8条评论

77

为了避免隐式类型转换(TypeScript等语言不喜欢此类情况),您可以使用 Number() 将布尔值显式转换为数字:

a = [false, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, false, true, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false];
a.sort(function(x, y) {
   return Number(x) - Number(y);
});
console.log(a);

或者使用箭头函数:

a = [false, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, false, true, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false];
a.sort((x, y) => Number(x) - Number(y));
console.log(a);


4
请注意:这种比较函数无法处理输入数组中的“undefined”值。 - JabbyPanda

51

更简单的方法:

a = [{xx:true},{xx:false},{xx:true},{xx:false},{xx:true},{xx:false},{xx:true},{xx:false},{xx:true},{xx:false},{xx:true},{xx:false},{xx:true},{xx:false},{xx:true},{xx:false},{xx:true},{xx:false}];

a.sort(function(a,b){return a.xx-b.xx});

console.log(a);

如果你希望以另一种方式排序,可以在sort()之后调用a.reverse()。

编辑: 根据问题更新,已进行编辑以反映对对象数组进行排序而非布尔数组的要求。


1
@PranavNegandhi:问题在于我在编辑重新定义它之前就回答了这个问题... - dandavis
5
好的,如果你想要按另一种方式进行排序,可以在排序函数中交换ab的位置,而不是调用reverse()函数。 - Yulian

33

数组没有任何相等的位置,所以为什么不省略等号检查,总是返回-1或1。这种方法在TS中表现良好。

a.sort(x => x ? -1 : 1)
注意:我有点担心这会对排序函数的内部产生影响,但似乎能解决问题。
如果您想进行反向排序。
a.sort(x => !x ? -1 : 1)

2
完美的解决方案,我喜欢你简约的方法。 - ogostos
2
在对对象进行排序时,这种方法不能保证具有相等属性值(即 a.xx === b.xx)的对象在彼此之间保持相同的顺序。 - Peter
完美,兄弟,非常出色的解决方案。 - IonicMan

29

简单解决方案:

[true, false, true, false].sort((a, b) => b - a)

console.log([true, false, true, false].sort((a, b) => b - a));


哎呀,我没想到 false - true === -1,谢谢你! - mchl18

4
您可以直接按照以下方式操作:
const sortedData = data.sort(
  (a, b) => Number(b) - Number(a),
);

这个解决方案对Typescript也适用,因为将布尔值转换为数字是显式的。

3
我也遇到了这个问题,这是我的解决方法,希望能帮到你:
orders.sort((x, y) => {
   if (x === y) return 0;
   if (x) return -1;
   return 1;
});

3
以下是我在使用TypeScript Angular 2时有效的解决方案:
  let a = [{aa:"1",xx:true},{aa:"10",xx:false},{aa:"2",xx:true},{aa:"11",xx:false},{aa:"3",xx:true},{aa:"12",xx:false},{aa:"4",xx:true},{aa:"13",xx:false},{aa:"5",xx:true},{aa:"14",xx:false},{aa:"6",xx:true},{aa:"15",xx:false},{aa:"7",xx:true},{aa:"16",xx:false},{aa:"8",xx:true},{aa:"17",xx:false},{aa:"9",xx:true},{aa:"18",xx:false}];

    //a.sort(function(a,b){return a.xx-b.xx});
    a.sort(function (x, y) {
        // true values first
        return (x.xx === y.xx) ? 0 : x ? -1 : 1;
        // false values first
        // return (x === y)? 0 : x? 1 : -1;
    });
    return JSON.stringify(a);

谢谢您采用面向对象的方式,它起作用了。 - Santosh

2

我只是出于好玩而想看看是否可以在不使用? :运算符的情况下完成。

注意

这适用于所有可排序数据类型(字符串、数字),而不仅仅是原始布尔值。我不确定这是否比? :更快,而且它更加复杂。我只是厌倦了条件语句,这只是个人偏好。

  var b = [false, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, false, true, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false]
  .sort((a,b) => Number(a > b) * 2 - 1);

我可以将其转化为一个实用函数并赋予其有意义的名称:
  var sortOrder = {
    asc: (a,b) => Number(a > b) * 2 - 1,
    desc: (a,b) => Number(a < b) * 2 - 1
  }

那么我可以:

  var b = [false, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, false, true, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false]
  .sort(sortOrder.asc);

2
请注意,sort 可以使用任何数字,而不仅仅是 -1 或 1。因此,您可以使用 (a, b) => Number(a > b) - 0.5 来避免乘法。 - Xavier Stévenne

1

比较函数的一个很简单的解决方案是检查 a < b,当转换为数字时会得到0或1。然后我们想把0映射为-1,1映射为1。为了做到这一点,你可以乘以2再减去1。

data.sort(function (a, b) {
  return (a < b) * 2 - 1
}

或者只是
data.sort((a, b) => (a < b) * 2 - 1)

问题解决了!
如果你的任何值为null,它们将被视为false(null*2 === 0),而任何值为undefined的值将变成NaN(undefined*2 === NaN),这应该使它在任何排序方向上都是最后一个。

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