我看过很多关于排序的帖子,甚至还有一些关于多列排序的帖子。他们似乎都对列的数量及其名称,排序类型和方向有着深入的了解。
我需要:
标准可能如下所示:
[
{key: 'Employee', type: 'alpha', dir: 'asc'},
{key: 'ProjectCode', type: 'numeric', dir: 'desc'},
{key: 'WorkDate', type: 'date', dir: 'desc'}
]
测试数据:
data = [
{Employee: 'Harry Smith', ProjectCode: 3443, WorkDate: '1/5/18'},
{Employee: 'John Doe', ProjectCode: 3443, WorkDate: '1/7/18'},
{Employee: 'John Doe', ProjectCode: 3443, WorkDate: '1/5/18'},
{Employee: 'John Doe', ProjectCode: 4574, WorkDate: '1/5/18'},
{Employee: 'John Doe', ProjectCode: 3443, WorkDate: '1/6/18'},
{Employee: 'Harry Smith', ProjectCode: 3443, WorkDate: '1/7/18'}
];
结果数据:
[
{Employee: 'Harry Smith', ProjectCode: 3443, WorkDate: '1/7/18'},
{Employee: 'Harry Smith', ProjectCode: 3443, WorkDate: '1/5/18'},
{Employee: 'John Doe', ProjectCode: 4574, WorkDate: '1/5/18'},
{Employee: 'John Doe', ProjectCode: 3443, WorkDate: '1/7/18'},
{Employee: 'John Doe', ProjectCode: 3443, WorkDate: '1/6/18'},
{Employee: 'John Doe', ProjectCode: 3443, WorkDate: '1/5/18'}
]
那么如何构建一个可以使用这些条件的排序例程,并一次对所有条件键进行排序?意味着重复的员工将被排序在一起,并在其中重复项目代码一起排序,并在其中重复日期。
答案 0 :(得分:1)
我已经整理了一个相当简单的函数,它返回一个可以传递给Array.prototype.sort()
的范围函数:
function sortBy (criteria) {
const sign = { asc: 1, desc: -1 };
const sort = {
numeric: (a, b) => a - b,
date: (a, b) => new Date(a) - new Date(b),
alpha: (a, b) => a.localeCompare(b)
};
const compare = criteria.map(
({ key, type, dir }) => (a, b) => sign[dir] * sort[type](a[key], b[key])
);
return (a, b) => compare.reduce((result, fn) => result || fn(a, b), 0);
}
let criteria = [
{key: 'Employee', type: 'alpha', dir: 'asc'},
{key: 'ProjectCode', type: 'numeric', dir: 'desc'},
{key: 'WorkDate', type: 'date', dir: 'desc'}
];
let data = [
{Employee: 'Harry Smith', ProjectCode: 3443, WorkDate: '1/5/18'},
{Employee: 'John Doe', ProjectCode: 3443, WorkDate: '1/7/18'},
{Employee: 'John Doe', ProjectCode: 3443, WorkDate: '1/5/18'},
{Employee: 'John Doe', ProjectCode: 4574, WorkDate: '1/5/18'},
{Employee: 'John Doe', ProjectCode: 3443, WorkDate: '1/6/18'},
{Employee: 'Harry Smith', ProjectCode: 3443, WorkDate: '1/7/18'}
];
console.log(data.sort(sortBy(criteria)));
注意:作为Nina's answer states,reduce()
会迭代整个criteria
数组,而some()
会在第一个非零值处停止迭代,但是result || fn(...)
至少在每次迭代中使比较调用短路,因此没有不必要的标准比较被评估。
如果您有一个通用的排序标准,您还可以为您的排序方法提供可重复使用的功能:
const sortByMyCriteria = sortBy(criteria);
arrayA.sort(sortByMyCriteria);
arrayB.sort(sortByMyCriteria);
...
sortBy()
方法:function sortBy (criteria) {
var sign = { asc: 1, desc: -1 };
var sort = {
numeric: function (a, b) { return a - b; },
date: function (a, b) { return new Date(a) - new Date(b); },
alpha: function (a, b) { return a.localeCompare(b); }
};
var compare = criteria.map(function (c) {
var key = c.key, type = c.type, dir = c.dir;
return function (a, b) {
return sign[dir] * sort[type](a[key], b[key]);
};
});
return function (a, b) {
return compare.reduce(function (result, fn) {
return result || fn(a, b);
}, 0);
};
}
答案 1 :(得分:1)
您可以定义一些简单的函数来比较两个值,并将它们存储在一个对象中,以便通过sortCriteria对象的type
属性进行访问。
然后取Array#some
并使用排序结果作为返回值。此方法迭代直到数组结束或返回值为truthy,这是我们需要的值作为排序回调的返回值。在some
回调内部,方向与函数一起使用,以使用函数的两个参数重新调整相对值。
var data = [{ Employee: 'Harry Smith', ProjectCode: 3443, WorkDate: '1/5/18' }, { Employee: 'John Doe', ProjectCode: 3443, WorkDate: '1/7/18' }, { Employee: 'John Doe', ProjectCode: 3443, WorkDate: '1/5/18' }, { Employee: 'John Doe', ProjectCode: 4574, WorkDate: '1/5/18' }, { Employee: 'John Doe', ProjectCode: 3443, WorkDate: '1/6/18' }, { Employee: 'Harry Smith', ProjectCode: 3443, WorkDate: '1/7/18' }],
sortFn = {
alpha: function (a, b) { return a.localeCompare(b); },
numeric: function (a, b) { return a - b; },
date: function (a, b) { return new Date(a) - new Date(b); }
},
sortCriteria = [{ key: 'Employee', type: 'alpha', dir: 'asc' }, { key: 'ProjectCode', type: 'numeric', dir: 'desc' }, { key: 'WorkDate', type: 'date', dir: 'desc' }];
data.sort(function (a, b) {
var value = 0;
return sortCriteria.some(function (o) {
return value = (o.dir === 'asc' || -1) * sortFn[o.type](a[o.key], b[o.key]);
}) && value;
});
console.log(data);
.as-console-wrapper { max-height: 100% !important; top: 0; }
答案 2 :(得分:0)
使用其他帖子中的一些想法我想出了以下代码似乎工作正常并以正确的顺序返回数组。
data = [
{Employee: 'Harry Smith', ProjectCode: 3443, WorkDate: '1/5/18'},
{Employee: 'John Doe', ProjectCode: 3443, WorkDate: '1/7/18'},
{Employee: 'John Doe', ProjectCode: 3443, WorkDate: '1/5/18'},
{Employee: 'John Doe', ProjectCode: 4574, WorkDate: '1/5/18'},
{Employee: 'John Doe', ProjectCode: 3443, WorkDate: '1/6/18'},
{Employee: 'Harry Smith', ProjectCode: 3443, WorkDate: '1/7/18'}
];
sortCriteria = [
{key: 'Employee', type: 'alpha', dir: 'asc'},
{key: 'ProjectCode', type: 'numeric', dir: 'desc'},
{key: 'WorkDate', type: 'date', dir: 'desc'}
];
data.sort(function(a, b) {
var x, y, i;
for (i=0; i < sortCriteria.length; i++) {
x = a[sortCriteria[i].key];
y = b[sortCriteria[i].key];
if (sortCriteria[i].type === 'date') {
x = new Date(x).getTime();
y = new Date(y).getTime();
}
if (sortCriteria[i].type === 'numeric') {
x = parseFloat(x);
y = parseFloat(y);
}
if (sortCriteria[i].dir === 'asc') {
if (x < y) return -1;
if (x > y) return 1;
} else {
if (x > y) return -1;
if (x < y) return 1;
}
}
return 0;
});
console.log(data);
&#13;