#javascript #arrays #vue.js
Вопрос:
У меня есть два массива в Javascript, исходящие из Php. Я объединяю эти массивы в один массив.
Все элементы массивов имеют created_at
значение (Laravel). Я хочу отсортировать эти значения по created_at
Проблема: Независимо от их даты. Элементы первого массива никогда не располагаются позади элементов второго массива
Пример: B имеет последнюю дату. Но даже в этом случае C (происходит из второго массива) происходит после B.
Проблема в том, что я объединил эти два массива в один массив. Javascript все еще думает: «существует два массива. Я должен отсортировать элементы первого массива, а затем элементы второго массива».
Что мне делать, это :
history.push(...response.data[0]); // first array's values
history.push(...response.data[1]); // second array's values
history.sort((a, b) => {
return a.created_at - b.created_at;
});
итак, история, как
[
// Comes from first array
{
name: 'A',
created_at: '08/09/2021'
},
// Comes from first array
{
name: 'B',
created_at: '15/09/2021'
},
// This third element comes from second array.
{
name: 'C',
created_at: '08/09/2021'
}
]
Я ожидаю такого результата:
новая отсортированная история:
{
name: 'A',
created_at: '08/09/2021'
},
{
name: 'C',
created_at: '08/09/2021'
},
{
name: 'B',
created_at: '15/09/2021'
}
Но Javascript изначально сортирует элемент первого массива. После этого отсортируйте элемент второго массива, и тогда получится следующее:
{
name: 'A',
created_at: '08/09/2021'
},
{
name: 'B',
created_at: '15/09/2021'
},
{
name: 'C',
created_at: '08/09/2021'
},
Комментарии:
1. Порядок элементов — это именно то, как вы добавляете их в массив. Если вы хотите отсортировать массив, вам нужно явно это сделать.
2. Вам нужно отсортировать массив по дате ??
3. Ты так и не позвонил
history.sort()
. Почему вы ожидаете, что они будут переупорядочены?4. После объединения обоих ваших массивов вам нужно отсортировать их по history.sort((r1, r2) => { d1 = новая дата(r1.created_at); d2 = новая дата(r2.created_at); возврат d1 >> d2 ? 1 : (d1
5. JavaScript не выполняет автоматическую сортировку элементов массива при вставке. Не путайте понятие упорядоченного множества и отсортированного множества.
Ответ №1:
Вы можете array#concat
как свой массив, так и использовать Schwartzian transform
для сортировки массива путем преобразования created_at
в YYYY-MM-DD
формат, который может быть отсортирован лексикографически.
const arr1 = [{name: 'A', created_at: '08/09/2021'}],
arr2 = [{name: 'B', created_at: '15/09/2021'}, {name: 'C', created_at: '08/09/2021'}],
result = arr1.concat(arr2)
.map(o => [o.created_at.replace(/(..)/(..)/(....)/, '$3-$2-$1'), o])
.sort((a,b) => a[0].localeCompare(b[0]))
.map(([,o]) => o);
console.log(result)
Комментарии:
1. До «преобразования Шварца». Спасибо!
2. @HassanImam Можете ли вы объяснить или порекомендовать некоторые вещи о преобразовании Шварца. Я просмотрел несколько сайтов, но ничего не понял.
3. Это похоже на украшение, сортировку и отделку. На этапе декорирования мы создаем массив исходного объекта и преобразованной даты, который мы будем использовать при сортировке, это помогает нам избежать многократного преобразования дат. После сортировки мы возвращаем исходный объект с помощью
array#map
.
Ответ №2:
Вам нужно отправить пользовательскую функцию сортировки в Array.sort()
const array =
[
{ name: 'A', created_at: '08/09/2021' },
{ name: 'B', created_at: '15/09/2021' },
{ name: 'C', created_at: '08/09/2021' }
];
const ymd = (dmy) => { let a = dmy.split('/'); return a[2] '/' a[1] '/' a[0] }
const sorted = array.sort((elem1, elem2) => ymd(elem1.created_at) > ymd(elem2.created_at) ? 1 : -1);
console.log(sorted);
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort
Редактировать:
Если вам нужна стабильная сортировка (то есть она никогда произвольно не меняет объекты местами с эквивалентными значениями сравнения) или по дате первой и альфа-второй, вам понадобится более сложная функция сортировки.
Имея немного больше времени и localeCompare()
форму предложения Феликса Клинга, я написал улучшенную сортировку, которая стабильна и будет сортироваться по дате и имени во-вторых.
const array =
[
{ name: 'A', created_at: '08/09/2021' },
{ name: 'Z', created_at: '15/09/2021' },
{ name: 'D', created_at: '15/09/2021' },
{ name: 'B', created_at: '15/09/2021' },
{ name: 'C', created_at: '08/09/2021', stable: '1'},
{ name: 'S', created_at: '08/09/2020' },
{ name: 'C', created_at: '08/09/2021', stable: '2' },
{ name: 'C', created_at: '08/06/2021' }
];
const ymd = (dmy) => { let a = dmy.split('/'); return a[2] '/' a[1] '/' a[0] }
const sorted = array.sort((elem1, elem2) =>
(ymd(elem1.created_at) === ymd(elem2.created_at)) ?
elem1.name.localeCompare(elem2.name) :
ymd(elem1.created_at).localeCompare(ymd(elem2.created_at)));
console.log(sorted);
Выходы:
[
{ name: 'S', created_at: '08/09/2020' },
{ name: 'C', created_at: '08/06/2021' },
{ name: 'A', created_at: '08/09/2021' },
{ name: 'C', created_at: '08/09/2021', stable: '1' },
{ name: 'C', created_at: '08/09/2021', stable: '2' },
{ name: 'B', created_at: '15/09/2021' },
{ name: 'D', created_at: '15/09/2021' },
{ name: 'Z', created_at: '15/09/2021' }
]
Комментарии:
1. Вы не учитываете случай, когда обе даты равны (и должны возвращаться
0
после обратного вызова). Используйтеymd(elem1.created_at).localeCompare(ymd(elem2.created_at))
для упрощения сравнения. Но пока вы единственный, кто объясняет, что исходный формат даты не поддается сортировке.2. Вы правы, должна быть стабильная сортировка (0) и, вероятно, также в алфавитном порядке по названию, вот почему я упомянул об этом. Я постараюсь улучшить его сейчас, когда у меня есть немного времени.
Ответ №3:
Вы можете сначала попытаться объединить массив, а затем отсортировать полученный массив:
const arr1 = [{name: 'A', created_at: '08/09/2021'},]
const arr2 = [{name: 'B', created_at: '15/09/2021'}, {name: 'C', created_at: '08/09/2021'}]
const result = arr1.concat(arr2).sort((a , b) => a.created_at > b.created_at)
console.log(result)
Комментарии:
1. Это именно то, что я пробовал. Но мне так жаль, что я забыл добавить код сортировки. Итак, я сбил людей с толку. Теперь я добавил код. Как вы можете видеть, хотя у B есть последняя дата, она все еще находится перед C (второй массив).
2. Две проблемы: 1)
.sort
необходимо возвращать отрицательное число, 0 или положительное число, а не логическое значение. Возвращая логическое значение, вы рассматриваете все случаи, когдаa
оно меньше, чемb
еслиa
равноb
, что может привести к неправильному порядку. 2) Это может не сработать, если у вас есть даты из разных месяцев или лет. например22/01/2021
, они будут отсортированы последними. Это связано с тем, что даты отформатированы таким образом, чтобы их нельзя было сравнивать буквенно-цифровым способом.
Ответ №4:
Для сортировки по значениям дат вы можете использовать Date.prototype.getTime():
const arr1 = [{name: 'A', created_at: '08/09/2021'}]
const arr2 = [{name: 'B', created_at: '15/09/2021'}, {name: 'C', created_at: '08/09/2021'}]
const toNumber= d => d.replace(///g, '')
const result = [...arr1, ...arr2].sort((a, b) => toNumber(a.created_at) - toNumber(b.created_at))
console.log(result)
Комментарии:
1. Почему это должно быть неверно? Просто
Date
я не могу справиться с этим форматом.localeCompare
не получится, попробуй"22/01/2021"
на одно из свиданий.2. Вы должны объяснить, что вы изменили формат даты и почему вы это сделали.
3. Формат вашей даты неверен.. Вы должны попробовать
new Date('15/09/2021')
, и вы увидите ошибку4. Это не мое свидание. Я не задавал этого вопроса. Вы продолжаете говорить, что формат «неправильный»: даты могут быть отформатированы различными способами. Только потому
Date
, что не может обработать формат, не означаетdd/mm/yyy
, что это «неправильно». Есть страны, которые используют этот формат: en.wikipedia.org/wiki/Date_format_by_country5. Пожалуйста. Я мог бы яснее объяснить, почему формат даты не является «неправильным».