#javascript #arrays #sorting
#javascript #массивы #сортировка
Вопрос:
У меня есть массив, подобный этому:
var arrValues1 = [
[11, 58],
[18, 45],
[13, 23],
[15, 68],
[23, 32],
[45, 45],
[19, 68],
[88, 68]
];
Чтобы отсортировать его по индексу 1, я использовал следующую функцию:
sortIn(arr, prop) {
return arr.sort((a, b) => {
if (a[prop] > b[prop]) {
return 1;
} else if (a[prop] < b[prop]) {
return -1;
} else {
return 0;
}
});
}
arrValues2.push(sortIn(arrValues1, 1));
Итак, я получаю этот результат:
var arrValues2 = [
[13, 23],
[23, 32],
[45, 45],
[18, 45],
[11, 58],
[19, 68],
[88, 68],
[15, 68]
];
Моя проблема связана с повторяющимися значениями (45 и 68 в этом примере). Если у меня есть повторяющиеся значения, мне нужно отсортировать их с учетом значения индекса 0. Итак, конечный результат будет:
var arrValues2 = [
[13, 23],
[23, 32],
[18, 45],// > these 2 cases were reordered
[45, 45],//
[11, 58],
[15, 68],// > these 3 cases were reordered
[19, 68],//
[88, 68] //
];
Важно сохранить все позиции, изменяя только порядок повторяющихся значений. Как я могу этого добиться?
Ответ №1:
Вы можете добавить любое количество резервных свойств сортировки в качестве параметров rest для вашей функции. Итак, вы попытаетесь выполнить сортировку по каждому и только в том случае, если все они совпадают, затем вы возвращаетесь 0
к равенству:
var arrValues = [
[11, 58],
[18, 45],
[13, 23],
[15, 68],
[23, 32],
[45, 45],
[19, 68],
[88, 68]
];
function sortIn(arr, ...props) {
// ^^^^^^^^ take any amount of properties to sort by
return arr.sort((a, b) => {
//try sorting by each. If no `return` is reached
//the comparison will continue with the next
for (const prop of props) {
if (a[prop] > b[prop]) {
return 1;
} else if (a[prop] < b[prop]) {
return -1;
}
}
return 0; //if no return was hit for each property, then the items are equal
});
}
const result = sortIn(arrValues, 1, 0);
// pass secondary sorting property ^
//more compact display in the console
const displayResult = result.map(x => JSON.stringify(x));
console.log( displayResult );
.as-console-wrapper {max-height: 100% !important; top: 0}
Вы сохраняете универсальность вашей сортировки, потому что вы все равно можете сортировать все, что подчиняется операторам >
and <
:
var data = [
{foo: 3, bar: "a", baz: new Date("2020-01-01")},
{foo: 2, bar: "b", baz: new Date("2020-03-03")},
{foo: 1, bar: "b", baz: new Date("2020-03-03")},
{foo: 1, bar: "a", baz: new Date("2020-01-01")},
{foo: 3, bar: "b", baz: new Date("2020-03-03")},
{foo: 2, bar: "a", baz: new Date("2020-01-01")},
];
function sortIn(arr, ...props) {
return arr.sort((a, b) => {
for (const prop of props) {
if (a[prop] > b[prop]) {
return 1;
} else if (a[prop] < b[prop]) {
return -1;
}
}
return 0;
});
}
console.log( "foo --> bar --> baz" );
console.log( sortIn(data, "foo", "bar", "baz") );
console.log( "--------" );
console.log( "bar --> foo --> baz" );
console.log( sortIn(data, "bar", "foo", "baz") );
console.log( "--------" );
console.log( "baz --> foo --> bar" );
console.log( sortIn(data, "baz", "foo", "bar") );
console.log( "--------" );
.as-console-wrapper {max-height: 100% !important; top: 0}
Ответ №2:
Мы можем написать универсальный сортировщик, который принимает любое количество имен свойств, например:
const sorter = (...props) => (a, b) =>
props .reduce (
(result, p) => result || (a[p] < b[p] ? -1 : a[p] > b[p] ? 1 : 0),
0
)
// rearranged to demonstrate second-level sorting
const arrValues1 = [[11, 58], [45, 45], [13, 23], [19, 68], [15, 68], [23, 32], [18, 45], [88, 68]]
console .log (
arrValues1 .sort (sorter (1, 0))
)
.as-console-wrapper {max-height: 100% !important; top: 0}
Если вам нужен тот же интерфейс, вы можете использовать этот сортировщик внутри sortIn
, например:
const sortIn = (arr, ...props) =>
arr .sort (sorter (...props))
sortIn (arrValues1, 1, 0)
Или вы можете сложить его напрямую, как это:
const sortIn = (arr, ...props) =>
arr .sort ((a, b) =>
props .reduce (
(result, p) => result || (a[p] < b[p] ? -1 : a[p] > b[p] ? 1 : 0),
0
)
)
Я нахожу первую версию наиболее полезной. Я часто хочу создавать сортировщики, которые будут использоваться в нескольких местах. Но любой из них должен работать.
Ответ №3:
Вы можете передать два ключа в качестве параметров своей пользовательской функции. Затем сортировка с использованием второго реквизита, если они равны, затем проверьте первый реквизит в функции обратного вызова сортировки:
var arrValues1 = [
[11, 58],
[18, 45],
[13, 23],
[15, 68],
[23, 32],
[45, 45],
[19, 68],
[88, 68]
];
const sortIn = (arr, prop1, prop2) => {
return arr.sort((a, b) => a[prop1] - b[prop1] === 0 ?
a[prop2] - b[prop2] :
a[prop1] - b[prop1]);
}
console.log(sortIn(arrValues1, 1, 0))
Ответ №4:
Помимо приведенных ответов, этот подход требует некоторых замыканий над нужной упрощенной функцией сравнения и массивом ключей для сортировки, а также сравнения ключей с коротким замыканием, если возвращаемое значение отличается от ложного, в данном случае нулевого значения.
const
sortBy = fn => keys => (a, b) => {
let r;
keys.some(k => r = fn(a[k], b[k]));
return r;
}
array = [[11, 58], [18, 45], [13, 23], [15, 68], [23, 32], [45, 45], [19, 68], [88, 68]],
ascBy = sortBy((a, b) => a - b);
array.sort(ascBy([0, 1]));
console.log(array);
array.sort(ascBy([1, 0]));
console.log(array);
.as-console-wrapper { max-height: 100% !important; top: 0; }
Комментарии:
1. Неплохо. Я не стал беспокоиться о коротком замыкании в своем ответе, хотя сокращение несколько закорочено
||
. Более полное решение, вероятно, будет использовать произвольные функции, которые возвращают упорядоченный тип вместеascend
с /descend
helpers , возможно, с API что-то вроде:const mySorter = sortBy(descend(prop('age')), ascend(prop('lastName')), ascend(prop('firstName')))
, с местом для других функций, чем просто простые свойства объекта. Но это для другого вопроса…
Ответ №5:
воспользуйтесь уничтожением массива:
let arrValues1=[[11,58],[18,45],[13,23],[15,68],[23,32],[45,45],[19,68],[88,68]];
let result = arrValues1.sort(([i,j],[k,l]) => j === l?i-k:j-l)
console.log(result)
Ответ №6:
вы можете продолжить сортировку после того, как значения будут равны…:
const arrValues2 = [
[11, 58],
[18, 45],
[13, 23],
[15, 68],
[23, 32],
[45, 45],
[19, 68],
[88, 68]
];
function sort_vals(a ,b){
if (a[1] > b[1]) {
return 1;
} else if (a[1] < b[1]) {
return -1;
} else {
if(a[0] > b[0]){
return 1;
}else if(a[0] < b[0]){
return -1;
}
return 0
}
}
console.log(arrValues2.sort(sort_vals))
Ответ №7:
Вы можете упорядочить их, добавив больше логики в свой блок else следующим образом:
sortIn(arr, prop) {
return arr.sort((a, b) => {
if (a[prop] > b[prop]) {
return 1;
} else if (a[prop] < b[prop]) {
return -1;
} else {
if (a[0] > b[0]) {
return 1
} else {
return -1
}
}
});
}
arrValues2.push(sortIn(arrValues1, 1));
Ответ №8:
Вы можете сравнить снова в случае равенства, например
sortIn(arr, prop) {
return arr.sort((a, b) => {
if (a[prop] > b[prop]) {
return 1;
} else if (a[prop] < b[prop]) {
return -1;
} else {
// Compare Again
// return 0;
if (a[0] > b[0]) {
return 1;
} else if (a[0] < b[0]) {
return -1;
} else {
return 0;
}
}
});
}
arrValues2.push(sortIn(arrValues1, 1));