这是一个示例数据:
[
{
"name": "test",
"is_folder": "Y",
"is_file": "N",
"sort": 0,
"sort_reverse": 1
},
{
"name": "1.jpg",
"is_folder": "N",
"is_file": "Y",
"sort": 1,
"sort_reverse": 0
}
]
想法是,文件夹将始终位于列表的顶部,然后是文件,但我也希望对文件夹和文件进行排序。
结果示例:
升序(默认):
降序(反向):
如何通过示例数据实现这一目标?
到目前为止,这里是我对名称进行排序的内容,但没有考虑文件夹/文件的顺序:
items.sort((a: any, b: any) => {
if (a.name > b.name) {
return 1;
} else if (a.name < b.name) {
return -1;
} else {
return 0;
}
});
您可以简单地执行以下操作:
is_folder
属性相等,则它们都是文件,或者都是文件夹。比较他们的名字is_folder === "Y"
更高上升:
const arr = [
{ "name": "Folder 3", "is_folder": "Y" },
{ "name": "2.jpg", "is_folder": "N" },
{ "name": "Folder 2", "is_folder": "Y" },
{ "name": "Folder 10", "is_folder": "Y" },
{ "name": "Folder 1", "is_folder": "Y" },
{ "name": "15.jpg", "is_folder": "N" },
{ "name": "3.jpg", "is_folder": "N" },
{ "name": "abc.txt", "is_folder": "N" },
{ "name": "1.jpg", "is_folder": "N" },
];
arr.sort((a, b) => {
if (a.is_folder === b.is_folder)
return a.name.localeCompare(b.name, undefined, {numeric: true});
if (a.is_folder === "Y")
return -1;
if (b.is_folder === "Y")
return 1;
return 0;
});
console.log(arr)
降序:
const arr = [
{ "name": "Folder 3", "is_folder": "Y" },
{ "name": "2.jpg", "is_folder": "N" },
{ "name": "Folder 2", "is_folder": "Y" },
{ "name": "Folder 10", "is_folder": "Y" },
{ "name": "Folder 1", "is_folder": "Y" },
{ "name": "15.jpg", "is_folder": "N" },
{ "name": "3.jpg", "is_folder": "N" },
{ "name": "abc.txt", "is_folder": "N" },
{ "name": "1.jpg", "is_folder": "N" },
];
arr.sort((a, b) => {
if (a.is_folder === b.is_folder)
return b.name.localeCompare(a.name, undefined, {numeric: true}); //<-- flip `a` and `b`
if (a.is_folder === "Y")
return -1;
if (b.is_folder === "Y")
return 1;
return 0;
});
console.log(arr)
在TypeScript Playground上查看(包括类型)
使用localeCompare
与数字整理选项可以确保数字将被正确排序,其中10
为后 2
,例如。如果不使用它,将会发生以下情况:
const arr = [
{ "name": "Folder 3", "is_folder": "Y" },
{ "name": "2.jpg", "is_folder": "N" },
{ "name": "Folder 2", "is_folder": "Y" },
{ "name": "Folder 10", "is_folder": "Y" },
{ "name": "Folder 1", "is_folder": "Y" },
{ "name": "15.jpg", "is_folder": "N" },
{ "name": "3.jpg", "is_folder": "N" },
{ "name": "abc.txt", "is_folder": "N" },
{ "name": "1.jpg", "is_folder": "N" },
];
arr.sort((a, b) => {
if (a.is_folder === b.is_folder)
return a.name.localeCompare(b.name); //<-- no numeric collation
if (a.is_folder === "Y")
return -1;
if (b.is_folder === "Y")
return 1;
});
console.log(arr)
如您所见,我们基本上重复了所有代码以进行升序/降序排序。这使维护变得更加困难,但是我们可以改进它。我们可以将每个部分提取到一个单独的函数中:
幸运的是,对于的升/降,翻转和的顺序a
与b
乘以相同,-1
因为它localeCompare
返回一个数字-正,负或零。因此,我们只能使用一次逻辑,而不能重复两次:
const compareFoldersFirst = (a, b) => {
if (a.is_folder === "Y")
return -1;
if (b.is_folder === "Y")
return 1;
return 0;
}
const compareNameAsc = (a, b) => {
if (a.is_folder === b.is_folder)
return a.name.localeCompare(b.name, undefined, {numeric: true});
return 0;
}
const compareNameDesc = (a, b) => compareNameAsc(a, b) * -1;
实际上,我们可以泛化其中使用的逻辑compareNameDesc
-它只运行带有两个参数的函数并将其乘以-1
,因此我们可以创建一个reverse
可以颠倒任何排序顺序的泛型函数:
const reverse = compareFn => (a, b) => compareFn(a, b) * -1;
const compareNameDesc = reverse(compareNameAsc);
另外,我们可以略微更改每个比较的逻辑以使其完全自给自足,因为现在名称的排序取决于某个东西是否是文件夹。
const compareFoldersFirst = (a, b) => {
if (a.is_folder === b.is_folder)
return 0;
if (a.is_folder === "Y")
return -1;
if (b.is_folder === "Y")
return 1;
};
用布尔值和数字转换规则的“创造性用法”来表达的时间更短:
const compareFoldersFirst = (a, b) => Number(b.is_folder === "Y") - Number(a.is_folder === "Y");
无论如何,这使我们能够is_folder
从名称比较中删除检查,而我们仅剩下以下比较器:
const compareFoldersFirst = (a, b) => Number(b.is_folder === "Y") - Number(a.is_folder === "Y");
const compareNameAsc = (a, b) => a.name.localeCompare(b.name, undefined, {numeric: true});
const compareNameDesc = reverse(compareNameAsc);
我们几乎拥有所有需要的工具,只需一次添加更多的逻辑,然后再进行逆向转换,就可以生成所需的任何排序顺序。我们只需要能够轻松组成不同的比较器即可。为此,我们可以将排序归纳为以下内容:获得任意数量的排序函数。我们产生了一个新函数,它将逐个运行它们,直到一个返回非零结果为止。可以这样做
const comparer = (...comparers) =>
(a, b) => {
for(let compareFn of comparers){
const result = compareFn(a, b);
if (result !== 0)
return result;
}
}
但是可以使用使其更紧凑Array#reduce
。最后,使用helper compare
函数可以使代码更易于维护和组合:
const arr = [
{ "name": "Folder 3", "is_folder": "Y" },
{ "name": "2.jpg", "is_folder": "N" },
{ "name": "Folder 2", "is_folder": "Y" },
{ "name": "Folder 10", "is_folder": "Y" },
{ "name": "Folder 1", "is_folder": "Y" },
{ "name": "15.jpg", "is_folder": "N" },
{ "name": "3.jpg", "is_folder": "N" },
{ "name": "abc.txt", "is_folder": "N" },
{ "name": "1.jpg", "is_folder": "N" },
];
//helper function that takes any amount of compare functions
//produces a function that runs each until a non-zero result
const compare = (...comparers) =>
(a, b) => comparers.reduce(
(result, compareFn) => result || compareFn(a, b),
0
);
//reverse the result of any compare function after it runs:
const reverse = compareFn => (a, b) => compareFn (a, b) * -1;
//the basic comparer functions:
const compareFoldersFirst = (a, b) => Number(b.is_folder === "Y") - Number(a.is_folder === "Y");
const compareNameAsc = (a, b) => a.name.localeCompare(b.name, undefined, {numeric: true});
const compareNameDesc = reverse(compareNameAsc);
//final comparison function derived form the basic ones
const asc = compare(
compareFoldersFirst,
compareNameAsc
);
const desc = compare(
compareFoldersFirst,
compareNameDesc
);
console.log("--- Ascending sort ---\n", arr.sort(asc));
console.log("--- Descending sort ---\n", arr.sort(desc));
我已经应用了您的原始答案(请参阅更新的问题),但这似乎并未对文件进行排序。它只对文件夹排序
@J。你有错字吗
a.is_foler
->a.is_folder
确实是一个错字。我的错。面容
@ J.Do是否已添加指向TS游乐场的链接,该链接使用类型进行比较。这很有用,因为
(a: any, b: any)
允许像您必须滑过的小错字,如果您限制类型,则会发现错误,因为该属性不存在。