从这个最初的问题,我将如何在多个字段应用排序?
使用这种稍作调整的结构,我将如何排序城市(上升)和价格(下降)?
var homes = [
{"h_id":"3",
"city":"Dallas",
"state":"TX",
"zip":"75201",
"price":"162500"},
{"h_id":"4",
"city":"Bevery Hills",
"state":"CA",
"zip":"90210",
"price":"319250"},
{"h_id":"6",
"city":"Dallas",
"state":"TX",
"zip":"75000",
"price":"556699"},
{"h_id":"5",
"city":"New York",
"state":"NY",
"zip":"00010",
"price":"962500"}
];
我喜欢的事实是,给出的答案提供了一个一般的方法。在我计划使用这段代码的地方,我将不得不对日期以及其他东西进行排序。“启动”对象的能力似乎很方便,如果不是有点麻烦的话。
我试图把这个答案构建成一个很好的通用示例,但我运气不太好。
按多个字段排序对象数组的最简单方法:
let homes = [ {"h_id":"3",
"city":"Dallas",
"state":"TX",
"zip":"75201",
"price":"162500"},
{"h_id":"4",
"city":"Bevery Hills",
"state":"CA",
"zip":"90210",
"price":"319250"},
{"h_id":"6",
"city":"Dallas",
"state":"TX",
"zip":"75000",
"price":"556699"},
{"h_id":"5",
"city":"New York",
"state":"NY",
"zip":"00010",
"price":"962500"}
];
homes.sort((a, b) => (a.city > b.city) ? 1 : -1);
输出:
“Bevery山”
“达拉斯”
“达拉斯”
“达拉斯”
“纽约”
以下是我的简历,请参考,并举例说明:
function msort(arr, ...compFns) {
let fn = compFns[0];
arr = [].concat(arr);
let arr1 = [];
while (arr.length > 0) {
let arr2 = arr.splice(0, 1);
for (let i = arr.length; i > 0;) {
if (fn(arr2[0], arr[--i]) === 0) {
arr2 = arr2.concat(arr.splice(i, 1));
}
}
arr1.push(arr2);
}
arr1.sort(function (a, b) {
return fn(a[0], b[0]);
});
compFns = compFns.slice(1);
let res = [];
arr1.map(a1 => {
if (compFns.length > 0) a1 = msort(a1, ...compFns);
a1.map(a2 => res.push(a2));
});
return res;
}
let tstArr = [{ id: 1, sex: 'o' }, { id: 2, sex: 'm' }, { id: 3, sex: 'm' }, { id: 4, sex: 'f' }, { id: 5, sex: 'm' }, { id: 6, sex: 'o' }, { id: 7, sex: 'f' }];
function tstFn1(a, b) {
if (a.sex > b.sex) return 1;
else if (a.sex < b.sex) return -1;
return 0;
}
function tstFn2(a, b) {
if (a.id > b.id) return -1;
else if (a.id < b.id) return 1;
return 0;
}
console.log(JSON.stringify(msort(tstArr, tstFn1, tstFn2)));
//output:
//[{"id":7,"sex":"f"},{"id":4,"sex":"f"},{"id":5,"sex":"m"},{"id":3,"sex":"m"},{"id":2,"sex":"m"},{"id":6,"sex":"o"},{"id":1,"sex":"o"}]
您可以使用lodash或derby函数lodash
它有两个参数字段数组和方向数组('asc','desc')
var homes = [
{"h_id":"3",
"city":"Dallas",
"state":"TX",
"zip":"75201",
"price":"162500"},
{"h_id":"4",
"city":"Bevery Hills",
"state":"CA",
"zip":"90210",
"price":"319250"},
{"h_id":"6",
"city":"Dallas",
"state":"TX",
"zip":"75000",
"price":"556699"},
{"h_id":"5",
"city":"New York",
"state":"NY",
"zip":"00010",
"price":"962500"}
];
var sorted =. data._.orderBy(data, ['city', 'price'], ['asc','desc'])
我一直在寻找类似的东西,最后得到了这个:
首先,我们有一个或多个排序函数,总是返回0、1或-1:
const sortByTitle = (a, b): number =>
a.title === b.title ? 0 : a.title > b.title ? 1 : -1;
您可以为想要排序的其他属性创建更多函数。
然后我有一个函数将这些排序函数合并为一个:
const createSorter = (...sorters) => (a, b) =>
sorters.reduce(
(d, fn) => (d === 0 ? fn(a, b) : d),
0
);
这可以用来以一种可读的方式组合上述排序函数:
const sorter = createSorter(sortByTitle, sortByYear)
items.sort(sorter)
当一个排序函数返回0时,将调用下一个排序函数进行进一步排序。
这是一个通用的多维排序,允许在每个层次上进行反转和/或映射。
用Typescript编写。对于Javascript,请查看这个JSFiddle
的代码
type itemMap = (n: any) => any;
interface SortConfig<T> {
key: keyof T;
reverse?: boolean;
map?: itemMap;
}
export function byObjectValues<T extends object>(keys: ((keyof T) | SortConfig<T>)[]): (a: T, b: T) => 0 | 1 | -1 {
return function(a: T, b: T) {
const firstKey: keyof T | SortConfig<T> = keys[0];
const isSimple = typeof firstKey === 'string';
const key: keyof T = isSimple ? (firstKey as keyof T) : (firstKey as SortConfig<T>).key;
const reverse: boolean = isSimple ? false : !!(firstKey as SortConfig<T>).reverse;
const map: itemMap | null = isSimple ? null : (firstKey as SortConfig<T>).map || null;
const valA = map ? map(a[key]) : a[key];
const valB = map ? map(b[key]) : b[key];
if (valA === valB) {
if (keys.length === 1) {
return 0;
}
return byObjectValues<T>(keys.slice(1))(a, b);
}
if (reverse) {
return valA > valB ? -1 : 1;
}
return valA > valB ? 1 : -1;
};
}
用法示例
先按姓排序,再按名排序:
interface Person {
firstName: string;
lastName: string;
}
people.sort(byObjectValues<Person>(['lastName','firstName']));
按语言代码的名称排序,而不是按语言代码排序(见地图),然后按降序排序(见反向)。
interface Language {
code: string;
version: number;
}
// languageCodeToName(code) is defined elsewhere in code
languageCodes.sort(byObjectValues<Language>([
{
key: 'code',
map(code:string) => languageCodeToName(code),
},
{
key: 'version',
reverse: true,
}
]));