sort Javascript array by two numeric fields

grouperArray.sort(function (a, b) {
var aSize = a.gsize;
var bSize = b.gsize;
var aLow = a.glow;
var bLow = b.glow;
console.log(aLow + " | " + bLow);
return (aSize < bSize) ? -1 : (aSize > bSize) ? 1 : 0;
});

This code sorts the array by gsize, smallest to largest.

How would I change it to sort first by gsize and then by glow?

115707 次浏览
grouperArray.sort(function (a, b) {
var aSize = a.gsize;
var bSize = b.gsize;
var aLow = a.glow;
var bLow = b.glow;
console.log(aLow + " | " + bLow);


if(aSize == bSize)
{
return (aLow < bLow) ? -1 : (aLow > bLow) ? 1 : 0;
}
else
{
return (aSize < bSize) ? -1 : 1;
}
});
grouperArray.sort(function (a, b) {
var aSize = a.gsize;
var bSize = b.gsize;
var aLow = a.glow;
var bLow = b.glow;
console.log(aLow + " | " + bLow);
return (aSize < bSize) ? -1 : (aSize > bSize) ? 1 : ( (aLow < bLow ) ? -1 : (aLow > bLow ) ? 1 : 0 );
});
grouperArray.sort(function (a, b) {
var aSize = a.gsize;
var bSize = b.gsize;
var aLow = a.glow;
var bLow = b.glow;
console.log(aLow + " | " + bLow);
return (aSize < bSize) ? -1 : (aSize > bSize) ? 1 : (aLow < bLow) ? -1 : (aLow > bLow) ? 1 : 0); });
grouperArray.sort(function (a, b) {
var aSize = a.gsize;
var bSize = b.gsize;
if (aSize !== aSize)
return aSize - bSize;
return a.glow - b.glow;
});

没有经过测试,但我觉得应该可以。

我估计 三元操作员 ((aSize < bSize) ? -1 : (aSize > bSize) ? 1 : 0;)让你感到困惑。你应该检查一下这个链接,以便更好地理解它。

在此之前,这里是您的代码吹成完整的 if/else。

grouperArray.sort(function (a, b) {
if (a.gsize < b.gsize)
{
return -1;
}
else if (a.gsize > b.gsize)
{
return 1;
}
else
{
if (a.glow < b.glow)
{
return -1;
}
else if (a.glow > b.glow)
{
return 1;
}
return 0;
}
});
grouperArray.sort(
function(a,b){return a.gsize == b.gsize ? a.glow - b.glow : a.gsize - b.gsize}
);

我就用这个

function sort(a, b) {
var _a = "".concat(a.size, a.glow);
var _b = "".concat(b.size, b.glow);
return _a < _b;
}

将这两个项连接为字符串,并按字符串值对它们进行排序。如果你知道它们是数字,你可以用 parseInt 包装 _ a 和 _ b,将它们作为数字进行比较。

I realize this was asked some time ago, but I thought I would add my solution.

此函数动态生成排序方法。只需提供每个可排序的子属性名,后面加上 +/-表示升序或降序顺序。超级可重用,而且它不需要知道任何关于您已经放在一起的数据结构。可能是白痴的证据,但似乎没有必要。

function getSortMethod(){
var _args = Array.prototype.slice.call(arguments);
return function(a, b){
for(var x in _args){
var ax = a[_args[x].substring(1)];
var bx = b[_args[x].substring(1)];
var cx;


ax = typeof ax == "string" ? ax.toLowerCase() : ax / 1;
bx = typeof bx == "string" ? bx.toLowerCase() : bx / 1;


if(_args[x].substring(0,1) == "-"){cx = ax; ax = bx; bx = cx;}
if(ax != bx){return ax < bx ? -1 : 1;}
}
}
}

例子用法:

items.sort(getSortMethod('-price', '+priority', '+name'));

这将排序 items与最低的 price第一,与领带的项目与最高的 priority。进一步的关系被物品 name打破

其中条目是一个数组,如:

var items = [
{ name: "z - test item", price: "99.99", priority: 0, reviews: 309, rating: 2 },
{ name: "z - test item", price: "1.99", priority: 0, reviews: 11, rating: 0.5 },
{ name: "y - test item", price: "99.99", priority: 1, reviews: 99, rating: 1 },
{ name: "y - test item", price: "0", priority: 1, reviews: 394, rating: 3.5 },
{ name: "x - test item", price: "0", priority: 2, reviews: 249, rating: 0.5 } ...
];

现场演示: http://gregtaff.com/misc/multi_field_sort/

EDIT: Fixed issue with Chrome.

grouperArray.sort(function (a, b) {
return a.gsize - b.gsize || a.glow - b.glow;
});

更短的版本

这里有一个实现,适用于那些希望使用任意数量字段的更通用的东西的用户。

Array.prototype.sortBy = function (propertyName, sortDirection) {


var sortArguments = arguments;
this.sort(function (objA, objB) {


var result = 0;
for (var argIndex = 0; argIndex < sortArguments.length && result === 0; argIndex += 2) {


var propertyName = sortArguments[argIndex];
result = (objA[propertyName] < objB[propertyName]) ? -1 : (objA[propertyName] > objB[propertyName]) ? 1 : 0;


//Reverse if sort order is false (DESC)
result *= !sortArguments[argIndex + 1] ? 1 : -1;
}
return result;
});


}

基本上,您可以指定任意数量的属性名/排序方向:

var arr = [{
LastName: "Doe",
FirstName: "John",
Age: 28
}, {
LastName: "Doe",
FirstName: "Jane",
Age: 28
}, {
LastName: "Foo",
FirstName: "John",
Age: 30
}];


arr.sortBy("LastName", true, "FirstName", true, "Age", false);
//Will return Jane Doe / John Doe / John Foo


arr.sortBy("Age", false, "LastName", true, "FirstName", false);
//Will return John Foo / John Doe / Jane Doe
grouperArray.sort((a, b) => a.gsize - b.gsize || a.glow - b.glow);

更短的版本使用箭头语法!

下面是一个实现,它使用递归按从1到无限的任意数量的排序字段进行排序。传递给它的结果数组是要排序的结果对象数组,排序数组是定义排序的排序对象数组。每个排序对象必须有一个“选择”键作为它进行排序的键名,以及一个“订单”键,它是一个指示“升序”或“降序”的字符串。

sortMultiCompare = (a, b, sorts) => {
let select = sorts[0].select
let order = sorts[0].order
if (a[select] < b[select]) {
return order == 'ascending' ? -1 : 1
}
if (a[select] > b[select]) {
return order == 'ascending' ? 1 : -1
}
if(sorts.length > 1) {
let remainingSorts = sorts.slice(1)
return this.sortMultiCompare(a, b, remainingSorts)
}
return 0
}


sortResults = (results, sorts) => {
return results.sort((a, b) => {
return this.sortMultiCompare(a, b, sorts)
})
}


// example inputs
const results = [
{
"LastName": "Doe",
"FirstName": "John",
"MiddleName": "Bill"
},
{
"LastName": "Doe",
"FirstName": "Jane",
"MiddleName": "Bill"
},
{
"LastName": "Johnson",
"FirstName": "Kevin",
"MiddleName": "Bill"
}
]


const sorts = [
{
"select": "LastName",
"order": "ascending"
},
{
"select": "FirstName",
"order": "ascending"
},
{
"select": "MiddleName",
"order": "ascending"
}
]


// call the function like this:
let sortedResults = sortResults(results, sorts)

下面是这种情况下的解决方案,当您有一个优先级排序键时,它可能不存在于某些特定的项中,因此您必须按回退键进行排序。

输入数据示例(表格 ID2是优先级排序键) :

const arr = [
{id: 1},
{id: 2, id2: 3},
{id: 4},
{id: 3},
{id: 10, id2: 2},
{id: 7},
{id: 6, id2: 1},
{id: 5},
{id: 9, id2: 2},
{id: 8},
];

产出应该是:

[ { id: 6, id2: 1 },
{ id: 9, id2: 2 },
{ id: 10, id2: 2 },
{ id: 2, id2: 3 },
{ id: 1 },
{ id: 3 },
{ id: 4 },
{ id: 5 },
{ id: 7 },
{ id: 8 } ]

比较器功能将类似于:

arr.sort((a,b) => {
if(a.id2 || b.id2) {
if(a.id2 && b.id2) {
if(a.id2 === b.id2) {
return a.id - b.id;
}
return a.id2 - b.id2;
}
return a.id2 ? -1 : 1;
}
return a.id - b.id
});

如果 .id可以为零,考虑使用 typeof

使用多个键进行此操作的一种动态方法是:

  • 从排序的每个 col/键过滤唯一值
  • 按顺序排列或反向排列
  • 根据 indexOf (value)键值为每个对象添加权重宽度零点
  • 使用计算出的权重进行排序

enter image description here

Object.defineProperty(Array.prototype, 'orderBy', {
value: function(sorts) {
sorts.map(sort => {
sort.uniques = Array.from(
new Set(this.map(obj => obj[sort.key]))
);


sort.uniques = sort.uniques.sort((a, b) => {
if (typeof a == 'string') {
return sort.inverse ? b.localeCompare(a) : a.localeCompare(b);
}
else if (typeof a == 'number') {
return sort.inverse ? (a < b) : (a > b ? 1 : 0);
}
else if (typeof a == 'boolean') {
let x = sort.inverse ? (a === b) ? 0 : a? -1 : 1 : (a === b) ? 0 : a? 1 : -1;
return x;
}
return 0;
});
});


const weightOfObject = (obj) => {
let weight = "";
sorts.map(sort => {
let zeropad = `${sort.uniques.length}`.length;
weight += sort.uniques.indexOf(obj[sort.key]).toString().padStart(zeropad, '0');
});
//obj.weight = weight; // if you need to see weights
return weight;
}


this.sort((a, b) => {
return weightOfObject(a).localeCompare( weightOfObject(b) );
});


return this;
}
});

用途:

// works with string, number and boolean
let sortered = your_array.orderBy([
{key: "type", inverse: false},
{key: "title", inverse: false},
{key: "spot", inverse: false},
{key: "internal", inverse: true}
]);

enter image description here

在我的例子中,我按参数‘ important’和‘ date’对通知列表进行排序

  • step 1: i filter notifications by 'important' and unImportant

    let importantNotifications = notifications.filter(
    (notification) => notification.isImportant);
    
    
    let unImportantNotifications = notifications.filter(
    (notification) => !notification.isImportant);
    
  • 第二步: 按日期排序

      sortByDate = (notifications) => {
    return notifications.sort((notificationOne, notificationTwo) => {
    return notificationOne.date - notificationTwo.date;
    });
    };
    
  • 第三步: 合并他们

    [
    ...this.sortByDate(importantNotifications),
    ...this.sortByDate(unImportantNotifications),
    ];
    

如果您乐意使用新的 tidy.js package,您可以使用

tidy(input_array,
arrange(['var1', desc('var2')])
);

让我们简化一下。

假设您有一个数组数组:

let tmp = [
[0, 1],
[2, 1],
[1, 1],
[0, 0],
[2, 0],
[1, 0],
[0, 2],
[2, 2],
[1, 2],
]

执行:

tmp.sort((a, b) => {
if (a[1] != b[1])
return a[1] - b[1];
else
return a[0] - b[0];
})

Will yield:

[
[0, 0],
[1, 0],
[2, 0],
[0, 1],
[1, 1],
[2, 1],
[0, 2],
[1, 2],
[2, 2]
]

除了这里的其他答案之外,我在数组中得到了不一致的数据,其中1希望在字段 x 上使用主 ASC 排序,在字段 y 上使用辅助 DESC 排序。
解决方案是通过将数字乘以 let say 1000000000来增加主排序的重要性

arrayOfObjects.sort((a, b) => {
return (
// Multiply by a high number to the most important sort, that makes them heavier than the second sort


// First sort ASC (notice the - minus in the end instead of the || in other answers !)
(a.paramX * 1000000000) -
(b.paramX * 1000000000) -


// Second sort DESC (switch them if you want ASC too)
(a.paramY - b.paramY)
)
})

对对象上的多个日期进行排序的方法是:

// param date1 ASC and param date2 DESC
arrayOfObjects.sort((a, b) => {
return (
(a.date1.getTime() * 1000000000) -
(b.date1.getTime() * 1000000000) -
(a.date2.getTime() - b.date2.getTime())
)
})
var items = [
{ name: "z - test item", price: "99.99", priority: 0, reviews: 309, rating: 2 },
{ name: "z - test item", price: "1.99", priority: 0, reviews: 11, rating: 0.5 },
{ name: "y - test item", price: "99.99", priority: 1, reviews: 99, rating: 1 },
{ name: "y - test item", price: "0", priority: 1, reviews: 394, rating: 3.5 },
{ name: "x - test item", price: "0", priority: 2, reviews: 249, rating: 0.5 }];


items.sort(function (a, b) {
var nameA = a.name.toUpperCase();
var nameB = b.name.toUpperCase();
var nameC = a.price.toUpperCase();
var nameD = b.price.toUpperCase();


if (nameA < nameB) {
return -1;
}
if (nameA > nameB || nameC > nameD) {
return 1;
}


// names must be equal
return 0;
});`