Привет всем, мне нужна помощь в сортировке массива таких объектов:
[
{
"jobID": "202012101329yXHTXvqg",
"jobDate": "12-10-2020",
"jobStart": "13:29:26",
"jobEnd": "13:31:58"
},
{
"jobID": "2020121013290Yyjny8x",
"jobDate": "12-10-2020",
"jobStart": "13:29:58",
"jobEnd": "13:30:36"
},
{
"jobID": "202011120928w28NDLQVu",
"jobDate": "12-11-2020",
"jobStart": "09:28:09",
"jobEnd": "09:28:25"
},
{
"jobID": "202011120927afObyUv8",
"jobDate": "12-11-2020",
"jobStart": "09:27:42",
"jobEnd": "09:27:58"
}
]
Я хотел бы отсортировать его по jobDate и по jobEnd в порядке убывания:
[
{
"jobID": "202011120928w28NDLQVu",
"jobDate": "12-11-2020",
"jobStart": "09:28:09",
"jobEnd": "09:28:25"
},
{
"jobID": "202011120927afObyUv8",
"jobDate": "12-11-2020",
"jobStart": "09:27:42",
"jobEnd": "09:27:58"
},
{
"jobID": "202012101329yXHTXvqg",
"jobDate": "12-10-2020",
"jobStart": "13:29:26",
"jobEnd": "13:31:58"
},
{
"jobID": "2020121013290Yyjny8x",
"jobDate": "12-10-2020",
"jobStart": "13:29:58",
"jobEnd": "13:30:36"
}
]
Я пытался использовать различные методы, но я могу сортировать только по одному значению, вместо этого мне приходится сортировать сразу по двум значениям (jobsDate и jobsEnd). Как бы вы справились с этой проблемой?
@KienHT 1-я сортировка по jobDate и 2-я каждая jobDate должна быть отсортирована по jobsEnd.
Вы можете предоставить пользовательскую функцию для метода sort
. Внутри этой функции вам нужно создать Date
объект из jobDate
jobEnd
времени и использовать его для сортировки по описанию, как описано здесь: developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/….
"12-10-2020"
должен быть ММ-ДД-ГГГГ или ДД-ММ-ГГГГ?
@VLAZ да, это "ММ-ДД-ГГГГ"
Этот вопрос задает то же, что и этот: Как отсортировать массив объектов по нескольким полям?
var arr = [
{
"jobID": "202012101329yXHTXvqg",
"jobDate": "12-10-2020",
"jobStart": "13:29:26",
"jobEnd": "13:31:58"
},
{
"jobID": "2020121013290Yyjny8x",
"jobDate": "12-10-2020",
"jobStart": "13:29:58",
"jobEnd": "13:30:36"
},
{
"jobID": "202011120928w28NDLQVu",
"jobDate": "12-11-2020",
"jobStart": "09:28:09",
"jobEnd": "09:28:25"
},
{
"jobID": "202011120927afObyUv8",
"jobDate": "12-11-2020",
"jobStart": "09:27:42",
"jobEnd": "09:27:58"
}
];
//first sort it by jobDate
arr.sort(function(item1,item2){
return (new Date(item2.jobDate) - new Date(item1.jobEnd));
});
//then by jobEnd
arr.sort(function(item1,item2){
return (new Date(item2.jobEnd) - new Date(item1.jobEnd));
});
я думаю это поможет
1. "12-10-2020"
— нестандартный формат даты, поэтому new Date("12-10-2020")
будет зависеть от реализации. 2. то же самое для new Date("13:30:36")
, но еще более вероятно, что будут созданы недопустимые объекты даты. 3. Две сортировки просто означают, что данные будут отсортированы по второму критерию, а не по обоим.
@VLAZ Спасибо за исправление, буду иметь в виду этот сценарий :-)
к сожалению, это решение не является хорошим, потому что оно сначала сортирует массив по дате (и это нормально), а затем снова сортирует весь массив по времени (и разрушает предыдущую сортировку).
const jobDate = [
{
"jobID": "202012101329yXHTXvqg",
"jobDate": "12-10-2020",
"jobStart": "13:29:26",
"jobEnd": "13:31:58"
},
{
"jobID": "2020121013290Yyjny8x",
"jobDate": "12-10-2020",
"jobStart": "13:29:58",
"jobEnd": "13:30:36"
},
{
"jobID": "202011120928w28NDLQVu",
"jobDate": "12-11-2020",
"jobStart": "09:28:09",
"jobEnd": "09:28:25"
},
{
"jobID": "202011120927afObyUv8",
"jobDate": "12-11-2020",
"jobStart": "09:27:42",
"jobEnd": "09:27:58"
}
];
function sortDate() {
jobDate.sort((a,b) => {
const d = new Date(b.jobDate.split("-").reverse().join("-")) - new Date(a.jobDate.split("-").reverse().join("-"));
if (d === 0) {
return a.jobEnd.localeCompare(b.jobEnd);
}
return d;
});
console.info(jobDate);
}
//sortDate("jobDate");
sortDate();
Это тоже работает, но я отредактировал его, чтобы он соответствовал моему вопросу (сортировка по убыванию): function sortDate(arr) { arr.sort((a, b) => { const d = new Date(b.jobDate.split('-').reverse().join('-')) - new Date(a.jobDate.split('-').reverse().join('-')); if (d === 0) { return b.jobEnd.localeCompare(a.jobEnd); } return d; }); } sortDate(jobDate);
хорошо, это здорово.
Нужно просто написать функцию (sort), которая всегда в порядке убывания сначала сравнивает jobDate
s двух элементов, а в случае, если обе даты равны, продолжает сравнивать значения jobEnd
обоих элементов.
В случае jobDate
нужно либо правильно преобразовать каждое значение в тип Date
перед передачей его в compareDescending
, либо переформатировать его для прямого сравнения из MM-DD-YYYY
в YYYY-MM-DD
(что является текущим вариантом использования).
Оба строковых значения каждого jobEnd
можно сравнивать напрямую через compareDescending
, поскольку формат hh:mm:ss
предоставляется на базе 24
часов.
function sanitizeDateFormat(str) {
const [month, day, year] = str.split('-');
return [year, month, day].join('-');
}
function compareDescending(a, b) {
return ((a > b) && -1) || ((a < b) && 1) || 0;
}
function compareJobsByDateAndEndTime(a, b) {
return compareDescending(
// new Date(a.jobDate),
// new Date(b.jobDate)
sanitizeDateFormat(a.jobDate),
sanitizeDateFormat(b.jobDate)
) || compareDescending(
a.jobEnd,
b.jobEnd
);
}
console.info([{
"jobID": "2020121013290Yyjny8x",
"jobDate": "12-10-2020",
"jobStart": "13:29:58",
"jobEnd": "13:30:36"
}, {
"jobID": "202012101329yXHTXvqg",
"jobDate": "12-10-2020",
"jobStart": "13:29:26",
"jobEnd": "13:31:58"
}, {
"jobID": "202011120927afObyUv8",
"jobDate": "12-11-2020",
"jobStart": "09:27:42",
"jobEnd": "09:27:58"
}, {
"jobID": "202011120928w28NDLQVu",
"jobDate": "12-11-2020",
"jobStart": "09:28:09",
"jobEnd": "09:28:25"
}].sort(compareJobsByDateAndEndTime));
.as-console-wrapper { min-height: 100%!important; top: 0; }
Редактировать
Пожалуйста, вы можете объяснить, что он делает?
((a > b) && -1) || ((a < b) && 1) || 0
– Лука Донналоя
Ожидается, что функция сравнения, которая по умолчанию выполняет сравнение в порядке возрастания, вернет значение больше, чем ноль, в случае, если ее первый аргумент окажется каким-то образом «больше», чем ее второе значение; аналогично с возвращаемым значением ниже нуля, что указывает на то, что первый аргумент является второстепенным по сравнению со вторым аргументом. Возвращаемое значение Zero указывает на равенство порядка/последовательности обоих аргументов. Компаратор, который помогает сортировать в порядке убывания, затем должен перевернуть возвращаемые значения для большего и меньшего значения.
const arr = [
{
jobID: '202012101329yXHTXvqg',
jobDate: '12-10-2020',
jobStart: '13:29:26',
jobEnd: '13:31:58',
},
{
jobID: '2020121013290Yyjny8x',
jobDate: '12-10-2020',
jobStart: '13:29:58',
jobEnd: '13:30:36',
},
{
jobID: '202011120928w28NDLQVu',
jobDate: '12-11-2020',
jobStart: '09:28:09',
jobEnd: '09:28:25',
},
{
jobID: '202011120927afObyUv8',
jobDate: '12-11-2020',
jobStart: '09:27:42',
jobEnd: '09:27:58',
},
];
arr.sort((a, b) => {
const aDateAsArr = a.jobDate.split('-');
const aTimeASArr = a.jobEnd.split(':');
const bDateAsArr = b.jobDate.split('-');
const bTimeASArr = b.jobEnd.split(':');
const aDate = new Date(
+aDateAsArr[2],
+aDateAsArr[1],
+aDateAsArr[0],
+aTimeASArr[0],
+aTimeASArr[1],
+aTimeASArr[2],
);
const bDate = new Date(
+bDateAsArr[2],
+bDateAsArr[1],
+bDateAsArr[0],
+bTimeASArr[0],
+bTimeASArr[1],
+bTimeASArr[2],
);
return bDate.getTime() - aDate.getTime();
});
console.info(arr)
Спасибо, тоже хорошее решение.
Было подтверждено, что он хорошо работает с точки зрения функциональности, и разработан интуитивно.
используя sort()
Метод sort() сортирует элементы массива на месте и возвращает отсортированный массив. Порядок сортировки по умолчанию — восходящий, основанный на преобразовании элементов в строки и последующем сравнении их последовательностей значений кодовых единиц UTF-16.
с compareFunction
Если параметр compareFunction не указан, все неопределенные элементы массива сортируются путем преобразования их в строки и сравнения строк в порядке единиц кода UTF-16. Например, «банан» предшествует «вишня». В числовой сортировке 9 предшествует 80, но поскольку числа преобразуются в строки, «80» предшествует «9» в порядке Unicode. Все неопределенные элементы сортируются в конец массива.
ссылка: Array.prototype.sort()
let data=[
{
"jobID": "202012101329yXHTXvqg",
"jobDate": "12-10-2020",
"jobStart": "13:29:26",
"jobEnd": "13:31:58"
},
{
"jobID": "2020121013290Yyjny8x",
"jobDate": "12-10-2020",
"jobStart": "13:29:58",
"jobEnd": "13:30:36"
},
{
"jobID": "202011120928w28NDLQVu",
"jobDate": "12-11-2020",
"jobStart": "09:28:09",
"jobEnd": "09:28:25"
},
{
"jobID": "202011120927afObyUv8",
"jobDate": "12-11-2020",
"jobStart": "09:27:42",
"jobEnd": "09:27:58"
}
]
const compareJobDateThenEndTime = ((a, b) => {
return (new Date(b.jobDate) - new Date(a.jobDate)) || b.jobEnd.localeCompare(a.jobEnd);
})
let result = data.sort(compareJobDateThenEndTime);
console.info(result);
Очень чисто, и это тоже работает, спасибо.
Самая большая проблема здесь заключается в том, что ваша дата указана в формате ММ-ДД-ГГГГ, что означает, что ее необходимо изменить, чтобы ее можно было легко сравнить с другой датой. Проще всего преобразовать в ГГГГ-ММ-ДД (формат ISO 8601) - в этом случае лексикографическая сортировка аналогична хронологической сортировке, поэтому вы можете напрямую сравнивать две даты как строки. Времена можно уже так сравнивать.
С некоторой абстракцией и обобщением вы можете получить легко компостируемое решение:
/* library code */
const extractField = prop => x =>
x[prop];
const pipe = (first, ...fns) => (...args) =>
fns.reduce((result, fn) => fn(result), first(...args));
const compare = (normalise = x => x) => (a, b) =>
(a = normalise(a)) === (b = normalise(b))
? 0
: a > b
? 1
: -1;
const sortingBy = (...criteria) => (a, b) =>
criteria.reduce((acc, c) => acc || c(a, b), 0);
const flip = f => (a, b) =>
f(b, a);
/* /library code */
/* sorting code */
//MM-DD-YYYY to YYYY-MM-DD
const formatDate = str =>
str.replace(/(\d\d)-(\d\d)-(\d\d\d\d)/, "$3-$1-$2");
//get jobDate -> sort as formatted date
const comparableDate = pipe(extractField("jobDate"), formatDate);
const compareDatesAsc = compare(comparableDate);
const compareDatesDesc = flip(compareDatesAsc);
const compareTimesAsc = compare(extractField("jobEnd"));
const comparator = sortingBy(
compareDatesDesc,
compareTimesAsc
);
/* /sorting code */
const arr = [
{
"jobID": "202012101329yXHTXvqg",
"jobDate": "12-10-2020",
"jobStart": "13:29:26",
"jobEnd": "13:31:58"
},
{
"jobID": "2020121013290Yyjny8x",
"jobDate": "12-10-2020",
"jobStart": "13:29:58",
"jobEnd": "13:30:36"
},
{
"jobID": "202011120928w28NDLQVu",
"jobDate": "12-11-2020",
"jobStart": "09:28:09",
"jobEnd": "09:28:25"
},
{
"jobID": "202011120928w28NDLQVu",
"jobDate": "12-11-2019",
"jobStart": "10:28:09",
"jobEnd": "10:28:25"
},
{
"jobID": "202011120928w28NDLQVu",
"jobDate": "12-11-2021",
"jobStart": "09:58:09",
"jobEnd": "09:58:25"
},
{
"jobID": "202011120927afObyUv8",
"jobDate": "12-11-2020",
"jobStart": "09:27:42",
"jobEnd": "09:27:58"
}
]
arr.sort(comparator);
console.info(arr);
Это обобщенные критерии сравнения:
const compare = (normalise = x => x) => (a, b) =>
(a = normalise(a)) === (b = normalise(b))
? 0
: a > b
? 1
: -1;
Вы можете предоставить свою функцию нормализации, которая преобразует a
и b
во что-то, что можно легко сравнить, чтобы она могла работать для любого типа данных, который подчиняется операторам <
и >
, таким как числа, строки, даты и т. д.
Это обобщенный алгоритм сортировки:
const sortingBy = (...criteria) => (a, b) =>
criteria.reduce((acc, c) => acc || c(a, b), 0);
Он принимает любое количество критериев сортировки и будет проходить a
и b
через каждый, пока не будет возвращено что-то отличное от 0
.
Эти два позволяют нам обобщить любую сортировку как набор критериев.
Некоторые помощники также определяются как библиотечный код, поскольку они не относятся к операции сортировки:
extractField
не требует пояснений и извлекает поле по имени из объекта.pipe
— это небольшой вспомогательный метод для составления функций вместе: g(f(x)) = pipe(f, g)(x)
.flip
меняет местами аргументы функции. Полезно здесь, поскольку позволяет создавать противоположные критерии сортировки из существующих, поскольку compare(x, y)
должен быть симметрично противоположен compare(y, x)
.Помимо библиотечного кода, фактическая логика сортировки состоит из определения того, по чему мы сортируем и в каком порядке:
formatDate
— единственная пользовательская функция для преобразования даты в формат ISO8601.comparableDate
получен из существующих функций: извлечение jobDate
и форматированиеcompareDatesAsc
и compareTimesAsc
также являются критериями сортировки.compareDatesDesc
— это бесплатная обратная сортировка.comparator
, наконец, окончательная логика, основанная на двух существующих по порядку.Большое спасибо, я ценю ваши усилия, чтобы подробно объяснить ваш ответ, я узнал кое-что новое! Я изменил внутренний код, так что теперь он отправляет мне даты в формате ISO8601. Я думаю, что я обобщу часть сравнения, чтобы принять «jobDate», а не «jobEnd» или любые другие аргументы, которые вы хотите передать функции extraField, восходящая сортировка и сортировка по убыванию — очень приятный бонус :)
Хотя это был самый подробный ответ, который я получил, к сожалению, он не работает должным образом, потому что результат неверен (в отличие от других ответов с еще более простыми методами). Спасибо, в любом случае!
@LucaDonnaloia, какой ввод дает неправильный результат? Кажется, я получаю ожидаемые результаты при сортировке по убыванию.
посмотрите на свой выходной код: есть один элемент, последний из вывода, который не отсортирован, «12-11-2019» должен быть в начале вывода с другими днями, такими как 12-11-2019
@LucaDonnaloia ах, теперь я понимаю, что ты имеешь в виду. По возрастанию по дате, но по убыванию по времени, правильно?
это desc по дате и по времени в день, то есть: 1. 2020-12-11 18:00 2. 2020-12-11 08:00 3. 2020-12-10 12:30 4. 2020-12-08 08:00 5. 2020-12-08 06:00 6. 2020-07-31 16:00 7. 2019-12-31 08:00
@LucaDonnaloia Спасибо. Я, по-видимому, неправильно понял вопрос в первый раз, я думал, что вам нужны даты и время по возрастанию. Я обновил даты по убыванию и времени по возрастанию. Работает лучше, так как я хотел продемонстрировать, как изменить критерии сортировки с помощью flip
. Использование его для двух критериев сортировки: один по возрастанию, другой по убыванию, я думаю, является еще лучшим примером.
Что важнее другого? Скажем, если 2 объекта имеют одинаковую дату? или есть такое же время?