Как упорядочить массив объектов по дате и по времени сразу

Привет всем, мне нужна помощь в сортировке массива таких объектов:

[
    {
        "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). Как бы вы справились с этой проблемой?

Что важнее другого? Скажем, если 2 объекта имеют одинаковую дату? или есть такое же время?

KienHT 11.12.2020 11:12

@KienHT 1-я сортировка по jobDate и 2-я каждая jobDate должна быть отсортирована по jobsEnd.

Luca Donnaloia 11.12.2020 11:17

Вы можете предоставить пользовательскую функцию для метода sort. Внутри этой функции вам нужно создать Date объект из jobDatejobEnd времени и использовать его для сортировки по описанию, как описано здесь: developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/….

Oleksandr Sakun 11.12.2020 11:35

"12-10-2020" должен быть ММ-ДД-ГГГГ или ДД-ММ-ГГГГ?

VLAZ 11.12.2020 11:39

@VLAZ да, это "ММ-ДД-ГГГГ"

Luca Donnaloia 11.12.2020 11:49

Этот вопрос задает то же, что и этот: Как отсортировать массив объектов по нескольким полям?

Heretic Monkey 11.12.2020 16:52
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
1
6
113
6
Перейти к ответу Данный вопрос помечен как решенный

Ответы 6

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 11.12.2020 11:26

@VLAZ Спасибо за исправление, буду иметь в виду этот сценарий :-)

Hemang vora 11.12.2020 11:29

к сожалению, это решение не является хорошим, потому что оно сначала сортирует массив по дате (и это нормально), а затем снова сортирует весь массив по времени (и разрушает предыдущую сортировку).

Luca Donnaloia 11.12.2020 11:38

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);

Luca Donnaloia 11.12.2020 12:07

хорошо, это здорово.

sourav satyam 11.12.2020 12:10
Ответ принят как подходящий

Нужно просто написать функцию (sort), которая всегда в порядке убывания сначала сравнивает jobDates двух элементов, а в случае, если обе даты равны, продолжает сравнивать значения 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)

Спасибо, тоже хорошее решение.

Luca Donnaloia 11.12.2020 12:02

Было подтверждено, что он хорошо работает с точки зрения функциональности, и разработан интуитивно.

  • используя 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);

Очень чисто, и это тоже работает, спасибо.

Luca Donnaloia 11.12.2020 12:21

Самая большая проблема здесь заключается в том, что ваша дата указана в формате ММ-ДД-ГГГГ, что означает, что ее необходимо изменить, чтобы ее можно было легко сравнить с другой датой. Проще всего преобразовать в ГГГГ-ММ-ДД (формат 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, восходящая сортировка и сортировка по убыванию — очень приятный бонус :)

Luca Donnaloia 11.12.2020 13:10

Хотя это был самый подробный ответ, который я получил, к сожалению, он не работает должным образом, потому что результат неверен (в отличие от других ответов с еще более простыми методами). Спасибо, в любом случае!

Luca Donnaloia 11.12.2020 13:34

@LucaDonnaloia, какой ввод дает неправильный результат? Кажется, я получаю ожидаемые результаты при сортировке по убыванию.

VLAZ 11.12.2020 13:44

посмотрите на свой выходной код: есть один элемент, последний из вывода, который не отсортирован, «12-11-2019» должен быть в начале вывода с другими днями, такими как 12-11-2019

Luca Donnaloia 14.12.2020 11:22

@LucaDonnaloia ах, теперь я понимаю, что ты имеешь в виду. По возрастанию по дате, но по убыванию по времени, правильно?

VLAZ 14.12.2020 11:26

это 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

Luca Donnaloia 14.12.2020 12:11

@LucaDonnaloia Спасибо. Я, по-видимому, неправильно понял вопрос в первый раз, я думал, что вам нужны даты и время по возрастанию. Я обновил даты по убыванию и времени по возрастанию. Работает лучше, так как я хотел продемонстрировать, как изменить критерии сортировки с помощью flip. Использование его для двух критериев сортировки: один по возрастанию, другой по убыванию, я думаю, является еще лучшим примером.

VLAZ 14.12.2020 13:08

Другие вопросы по теме