Javascript 无法正确排序包含两个数组值的数组
Posted
技术标签:
【中文标题】Javascript 无法正确排序包含两个数组值的数组【英文标题】:Javascript doesn't sort correctly an array including two arrays' values 【发布时间】:2021-11-05 12:57:19 【问题描述】:我有两个来自 php 的 javascript 数组。我将这些数组合并为一个数组。
所有数组的元素都有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'
,
【问题讨论】:
元素的顺序正是你将它们添加到数组中的方式。如果你想对数组进行排序,那么你必须明确地这样做。 您需要按日期对数组进行排序吗?? 你从来没有打电话给history.sort()
。你为什么期望它们被重新排序?
合并两个数组后,您需要对其进行排序` history.sort((r1, r2) => d1 = new Date(r1.created_at); d2 = new Date(r2. created_at); 返回 d1 > d2 ? 1 : (d1
JavaScript 在插入时不会自动对数组元素进行排序。不要混淆 ordered set 和 sorted set 的概念。
【参考方案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)
【讨论】:
关于“施瓦茨变换”的 TIL。谢谢! @HassanImam 你能解释或推荐一些关于 Schwartzian Transform 的事情吗?我看过一些网站,但我不明白。 类似于装饰、排序和取消装饰。在装饰步骤中,我们创建了一个原始对象和转换日期的数组,我们将在排序期间使用它,它有助于我们避免多次日期转换。排序后,我们使用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
编辑:
如果您需要稳定的排序(这意味着它不会随意交换具有等效比较值的对象)或按日期优先和 alpha 第二,那么您将需要更复杂的排序功能。
用更多的时间和localeCompare()
Felix Kling 的建议表,我编写了一个改进的排序,它是稳定的,将按日期排序,然后按名称排序。
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'
]
【讨论】:
您没有考虑两个日期相等的情况(应该从回调中返回0
)。使用ymd(elem1.created_at).localeCompare(ymd(elem2.created_at))
来简化比较。但到目前为止,您是唯一一个导致原始日期格式不可排序的人。
你是对的,应该有一个稳定的排序 (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)
【讨论】:
这正是我尝试过的。但我很抱歉我忘了添加排序代码。所以,我让人们头脑混乱。现在我添加了代码。可以看到,虽然 B 有最新的日期,但它仍然在 C(第二个数组)的前面。 两个问题: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)
【讨论】:
为什么会不正确?只是Date
无法处理那种格式。 localeCompare
不起作用,请尝试 "22/01/2021"
选择其中一个日期。
您应该说明您更改了日期格式以及为什么这样做。
你的日期格式错误..你应该试试new Date('15/09/2021')
,你会看到错误
这不是我的约会对象。我没有问这个问题。你一直说格式是“错误的”:日期可以用各种方式格式化。仅仅因为Date
无法处理格式并不意味着dd/mm/yyy
是“错误的”。有些国家使用这种格式:en.wikipedia.org/wiki/Date_format_by_country
不客气。我本来可以更清楚为什么日期格式不是“不正确”的。以上是关于Javascript 无法正确排序包含两个数组值的数组的主要内容,如果未能解决你的问题,请参考以下文章
JavaScript中数组Array.sort()排序方法详解