JavaScript - 按照2个属性对对象数组进行排序

20

我想按照两个不同的属性对对象数组进行排序。

这些是我的对象

array = [{ resVal: "25FA15", resFlow: 49, resName: "Rendimiento Tri-Seal Completo", resPhoto: "Tri-Sealseries.png", resHP: 1.5 },
 { resVal: "25FA2", resFlow: 52, resName: "Rendimiento Tri-Seal Completo", resPhoto: "Tri-Sealseries.png", resHP: 2 },
{ resVal: "45FA2", resFlow: 53, resName: "Rendimiento Hi-Cap Completo", resPhoto: "HighCapseries.png", resHP: 2 },
{ resVal: "35FA2", resFlow: 59, resName: "Rendimiento Hi-Cap Completo", resPhoto: "HighCapseries.png", resHP: 2 }]

我想按照“resFlow”值最高,但“resHP”值最低的顺序对数组进行排序。

我希望我的数组排列方式如下:

array = [{ resVal: "25FA15", resFlow: 49, resName: "Rendimiento Tri-Seal Completo", resPhoto: "Tri-Sealseries.png", resHP: 1.5 },
{ resVal: "35FA2", resFlow: 59, resName: "Rendimiento Hi-Cap Completo", resPhoto: "HighCapseries.png", resHP: 2 },
{ resVal: "45FA2", resFlow: 53, resName: "Rendimiento Hi-Cap Completo", resPhoto: "HighCapseries.png", resHP: 2 },
 { resVal: "25FA2", resFlow: 52, resName: "Rendimiento Tri-Seal Completo", resPhoto: "Tri-Sealseries.png", resHP: 2 }]

希望有人可以帮助我。

谢谢。


2
你的意思是首先按照 resHP 从低到高排序,然后对于那些值相等的,按照 resFlow 从高到低排序? - Frxstrem
请在发布问题之前搜索。如果您滚动到链接问题的已接受答案之后,您将找到显示如何多个属性的答案。 - T.J. Crowder
@T.J.Crowder,这个重复目标太糟糕了。 - Nina Scholz
@T.J.Crowder 我找过了,但是也没有找到我的答案。 - Zuriel Rodriguez
1
@NinaScholz:那里的答案回答了这个问题,这是标准。我相信你可以找到其他四个答案。我们不需要又一个关于这个问题的答案。 - T.J. Crowder
这个回答解决了你的问题吗?如何按多个字段对对象数组进行排序? - Heretic Monkey
4个回答

47

对于指定的键和排序顺序,您可以使用链式方法。

该数组按以下属性排序

  • resHP升序,以及
  • resFlow降序。

它通过计算增量来实现,并反映了两个对象之间的关系。如果值为零,则两个值相等,并计算并返回下一个增量。

var array = [{ resVal: "25FA15", resFlow: 49, resName: "Rendimiento Tri-Seal Completo", resPhoto: "Tri-Sealseries.png", resHP: 1.5 }, { resVal: "25FA2", resFlow: 52, resName: "Rendimiento Tri-Seal Completo", resPhoto: "Tri-Sealseries.png", resHP: 2 }, { resVal: "45FA2", resFlow: 53, resName: "Rendimiento Hi-Cap Completo", resPhoto: "HighCapseries.png", resHP: 2 }, { resVal: "35FA2", resFlow: 59, resName: "Rendimiento Hi-Cap Completo", resPhoto: "HighCapseries.png", resHP: 2 }];

array.sort(function (a, b) {
    return a.resHP - b.resHP || b.resFlow - a.resFlow;
});

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


5
要求按resHP属性升序排序,对于任何平局,按resFlow属性降序排序。
现在,Javascript的Array.prototype.sort函数允许我们对数组进行排序。它接受一个参数,即"compareFunction"。compareFunction接受两个参数,它们是要比较的数组元素,并且必须返回它们在预期结果数组中的相对位置。
function compareFunction (itemA, itemB) {...}

compareFunction(a, b)函数返回一个数字,如果b在结果中排在a之前,则该数字大于零

compareFunction(a, b)函数返回一个数字,如果b在结果中排在a之后,则该数字小于零

compareFunction(a, b)函数返回,如果在排序数组时,ab被认为是相等的。例如,在对[5, 3, 5]进行排序时,两个5被认为是相等的,因此当调用compareFunction(5,5)时,数组应返回0。

对于字符串的排序,不需要提供compareFunction函数。根据规范,当未提供compareFunction时,会将数组中的每个值转换为字符串,然后进行排序。以下是一个示例:

console.log('["z", "ct", "a", "aa", "ab", "bc"].sort(): ', ["z", "ct", "a", "aa", "ab", "bc"].sort());

常见错误:

没有使用compareFunction进行数字比较

尽管按规定,compareFunction是可选的,但如果在对数字或其他对象进行排序时未提供它,可能导致不正确的结果。请看下面的例子:

console.log("[1, 2, 5, 3, 0, 20].sort(): ", [1, 2, 5, 3, 0, 20].sort());

这里20出现在3之前,因为每个数字在比较之前都被转换为字符串,由于在字典中“20”排在“3”之前(如果有这样的字典),所以它在结果中出现在“3”之上。

从compareFunction中返回布尔值而不是数字值

这是我在原始答案中的错误。

当您从compareFunction中返回布尔值而不是数字值时,布尔值会被转换为数字。也就是说,true将变成1,false将变成0,但您没有返回-1。

var array = [
  {
    compareThis: 1,
    originalIndex: 1
  },
  {
    compareThis: 2,
    originalIndex: 2
  },
  {
    compareThis: -1,
    originalIndex: 3
  },
  {
    compareThis: -2,
    originalIndex: 4
  }
];

console.log(array.sort((a, b) => a.compareThis > b.compareThis));

在这里,结果是未排序的同一数组,因为当2和-1进行比较时,比较2>-1返回false,被转换为0。但是,当compareFunction返回0时,它表示两个元素的顺序应该保持不变。因此,该数组不会被排序。

对此数组进行正确的排序方式如下:

var array = [
  {
    compareThis: 1,
    originalIndex: 1
  },
  {
    compareThis: 2,
    originalIndex: 2
  },
  {
    compareThis: -1,
    originalIndex: 3
  },
  {
    compareThis: -2,
    originalIndex: 4
  }
];

console.log(array.sort((a, b) => a.compareThis - b.compareThis));

因此,解决问题的正确方式是:

var array = [{ resVal: "25FA15", resFlow: 49, resName: "Rendimiento Tri-Seal Completo", resPhoto: "Tri-Sealseries.png", resHP: 1.5 },
 { resVal: "25FA2", resFlow: 52, resName: "Rendimiento Tri-Seal Completo", resPhoto: "Tri-Sealseries.png", resHP: 2 },
{ resVal: "45FA2", resFlow: 53, resName: "Rendimiento Hi-Cap Completo", resPhoto: "HighCapseries.png", resHP: 2 },
{ resVal: "35FA2", resFlow: 59, resName: "Rendimiento Hi-Cap Completo", resPhoto: "HighCapseries.png", resHP: 2 }];


// The requirement is to sort ascending by resHP property and then for any ties, sort descending by resFlow property.
/* array.sort(function(a, b) {
  if (a.resHP > b.resHP) {
    return 1;
  } else if (a.resHP === b.resHP) {
    if (a.resFlow > b.resFlow) {
      return -1;
    } else if (a.resFlow === b.resFlow) {
      return 0;
    } else {
      return 1;
    }
  } else {
    return -1;
  }
}); */

// Simplified to the following as we are working with numbers.
array.sort(function sortByResHP(a, b) {
  return (a.resHP - b.resHP) !== 0 ? (a.resHP - b.resHP) : (b.resFlow - a.resFlow);
});

console.log("Result: ", array);

当然,这可以进一步缩短,如其他答案所示。我保留了较长的compareFunction版本,以使其更易于阅读。

原始(不正确)答案

你可以使用Array#sort来实现:

array = [{ resVal: "25FA15", resFlow: 49, resName: "Rendimiento Tri-Seal Completo", resPhoto: "Tri-Sealseries.png", resHP: 1.5 },
 { resVal: "25FA2", resFlow: 52, resName: "Rendimiento Tri-Seal Completo", resPhoto: "Tri-Sealseries.png", resHP: 2 },
{ resVal: "45FA2", resFlow: 53, resName: "Rendimiento Hi-Cap Completo", resPhoto: "HighCapseries.png", resHP: 2 },
{ resVal: "35FA2", resFlow: 59, resName: "Rendimiento Hi-Cap Completo", resPhoto: "HighCapseries.png", resHP: 2 }]


array.sort(function(d1,d2) {
  if(d1.resHP == d2.resHP) {
    return d1.resFlow < d2.resFlow;
  } else {
    return d1.resHP > d2.resHP;
  }
});

console.log(array);

这是一个糟糕的例子,因为它没有遵守回调函数对于排序所期望的返回值。sort需要获得小于零、零或大于零的值。这个答案只返回了零和一。如果你反转d1d2,那就不太对称了。 - Nina Scholz
@NinaScholz 我以前没有注意到这个。谢谢你的解释! :) - Nisarg Shah
虽然我认为@NinaScholz的答案更简洁,但我想表扬nisarg对他们的回答进行了修正,并提供了详细的解释。干得好! - blueberry_chopsticks

2
这是一种通过多个值对对象数组进行排序的简单方法。
arr.sort((a,b) => a.firstVal.localeCompare(b.firstVal) || a.secondVal.localeCompare(b.secondVal))

在你的情况下,它将是这样的:

array.sort((a,b) => a.resHP.localeCompare(b.resHP) || b.resFlow.localeCompare(a.resFlow)

0

将其视为更通用的解决方案:

function sortArrayByTwoProperties(array, prop1, asc1 = true, prop2, asc2 = true) {
    return array.sort((a, b) => (
        (asc1 ? a[prop1] - b[prop1] : b[prop1] - a[prop1])
        || (asc2 ? a[prop2] - b[prop2] : b[prop2] - a[prop2])
    ));
}

array = [{ resVal: "25FA15", resFlow: 49, resName: "Rendimiento Tri-Seal Completo", resPhoto: "Tri-Sealseries.png", resHP: 1.5 },
 { resVal: "25FA2", resFlow: 52, resName: "Rendimiento Tri-Seal Completo", resPhoto: "Tri-Sealseries.png", resHP: 2 },
{ resVal: "45FA2", resFlow: 53, resName: "Rendimiento Hi-Cap Completo", resPhoto: "HighCapseries.png", resHP: 2 },
{ resVal: "35FA2", resFlow: 59, resName: "Rendimiento Hi-Cap Completo", resPhoto: "HighCapseries.png", resHP: 2 }]

// I want to sort the array by the higher "resFlow" value, but with the lowest "resHP" value.

// resHP ascending, resFlow descending
result = sortArrayByTwoProperties(array, "resHP", true, "resFlow", false);

console.log(result);

array_expected = [{ resVal: "25FA15", resFlow: 49, resName: "Rendimiento Tri-Seal Completo", resPhoto: "Tri-Sealseries.png", resHP: 1.5 },
{ resVal: "35FA2", resFlow: 59, resName: "Rendimiento Hi-Cap Completo", resPhoto: "HighCapseries.png", resHP: 2 },
{ resVal: "45FA2", resFlow: 53, resName: "Rendimiento Hi-Cap Completo", resPhoto: "HighCapseries.png", resHP: 2 },
 { resVal: "25FA2", resFlow: 52, resName: "Rendimiento Tri-Seal Completo", resPhoto: "Tri-Sealseries.png", resHP: 2 }]
 


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