Вы можете просто сделать следующее:
- Если свойство
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 (включая типы)
Использование localeCompare
с опцией сравнения числительных c гарантирует, что числа будут правильно отсортированы, например, 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
возвращает число - положительное, отрицательное или ноль. Таким образом, мы можем иметь только один логик c и не повторять его дважды:
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;
Мы можем обобщить логи c, используемые в compareNameDesc
- он просто запускает функцию с двумя параметрами и умножает его на -1
, поэтому мы можем сделать обобщенную c reverse
функцию, которая может изменить любой порядок сортировки:
const reverse = compareFn => (a, b) => compareFn(a, b) * -1;
const compareNameDesc = reverse(compareNameAsc);
Кроме того, мы можем немного изменить логи c каждое сравнение, чтобы сделать его полностью самодостаточным, так как прямо сейчас сортировка имени зависит от того, является ли что-то папкой или нет.
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;
};
Это даже короче до express с небольшим ... "творческим использованием" правил логического преобразования и преобразования чисел:
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);
У нас есть почти всех инструментов, которые нам нужны для любой сортировки Порядок, который мы хотим, добавив больше логи c один раз , а затем отменить или нет. Нам просто нужно уметь легко составлять разные компараторы. Для этого мы можем обобщить сортировку следующим образом: Мы получаем любое число функций сортировки. Мы создаем новую функцию, которая будет запускать их один за другим, пока один не вернет ненулевой результат, и в этот момент мы его вернем. Это можно сделать как
const comparer = (...comparers) =>
(a, b) => {
for(let compareFn of comparers){
const result = compareFn(a, b);
if (result !== 0)
return result;
}
}
, но можно сделать более компактным, используя Array#reduce
. В конце концов, код легче поддерживать и компоновать, используя вспомогательную функцию 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));
См. На игровой площадке TypeScript (включая типы)