javascript - 按多个属性对对象数组进行排序,包括嵌套数组中的对象
问题描述
我知道在这里多次问过类似的问题,但在我的情况下有些东西不起作用。我有一组具有以下结构的对象:
const items = [
{id: 100, title:'text', path: '1', readMessages: [
{text: 'foo', InsertDate: Moment}
], unreadMessages: [
{text: 'bar', InsertDate: Moment}, {text: 'baz', InsertDate: Moment}
]},
{id: 103, title:'else', path: '1.1', readMessages: [], unreadMessages: [
{text: 'cux', InsertDate: Moment},
{text: 'dux', InsertDate: Moment},
{text: 'tux', InsertDate: Moment}
]},
{id: 110, title:'another', path: '2', readMessages: [], unreadMessages: []}
]
我需要对这个数组进行以下排序:
- 未读消息数量
- 自上一条消息以来经过的时间
- 小路
需要考虑的重要事项:readMessages 和 unreadMessages 数组可能为空(其中之一或两者),InsertDate 是 Moment 对象,路径可能有 '1'、'1.1' '1.1.1' 结构。
最终,具有最多 unreadMessages 的对象应该位于列表顶部,然后是没有 unreadMessages 但具有 readMessages 的对象,然后是两个空数组。所有必须首先按消息数量(首先是大多数消息)排序,然后按 InsertDate(首先是较旧消息),然后按路径(升序 - 1、1.1、1.2、1.2.1、1.2.2、1.3、2 等) .
我试图做这样的事情:
const sortedItems = items.sort((a, b) => {
if (a.unreadMessages.length === b.unreadMessages.length) {
if (a.unreadMessages.length) {
if (a.unreadMessages[a.unreadMessages.length - 1].InsertDate === b.unreadMessages[a.unreadMessages.length - 1].InsertDate) {
return (a.path < b.path) ? -1 : (a.path > b.path) ? 1 : 0;
} else {
return (a.unreadMessages[a.unreadMessages.length - 1].InsertDate < b.unreadMessages[b.unreadMessages.length - 1].InsertDate) ? -1 : 1;
}
}
else if (a.readMessages.length) {
if (a.readMessages[a.readMessages.length - 1].InsertDate === b.readMessages[a.readMessages.length - 1].InsertDate) {
return (a.path < b.path) ? -1 : (a.path > b.path) ? 1 : 0;
} else {
return (a.unreadMessages[a.unreadMessages.length - 1].InsertDate < b.unreadMessages[b.unreadMessages.length - 1].InsertDate) ? -1 : 1;
}
}
} else {
return (a.unreadMessages.length < b.unreadMessages.length) ? -1 : 1;
}
}).reverse()
一方面,它确实将具有最多未读消息的对象放在首位,但它不按 InsertTime/path 排序。当我将其中一个问题标记为已读(将所有对象从 unreadMessages 移动到 readMessages)时,该对象出现在列表的最底部,在两个数组都为空的对象下方。
我认为按 Moment 对象排序可能有问题,所以我尝试了类似的方法moment(a.readMessages[a.readMessages.length - 1].InsertDate)
,但这没有帮助。
请问有什么建议吗?
解决方案
const items=[
{id:100,title:"text",path:"1",readMessages:[{id:1,text:"foo",InsertDate:"2020-07-19T07:14:01.000Z"}],unreadMessages:[{id:5,text:"bar",InsertDate:"2020-07-22T07:03:13.000Z"},{id:6,text:"baz",InsertDate:"2020-07-22T07:03:24.000Z"}]},
{id:103,title:"else",path:"1.1",readMessages:[],unreadMessages:[{id:3,text:"dux",InsertDate:"2020-07-22T07:02:57.000Z"},{id:4,text:"cux",InsertDate:"2020-07-22T07:03:06.000Z"},{id:2,text:"tux",InsertDate:"2020-07-23T10:35:40.000Z"}]},
{id:110,title:"another",path:"2",readMessages:[],unreadMessages:[]},
{id:111,title:"another",path:"3",readMessages:[],unreadMessages:[{id:7,text:"tux",InsertDate:"2020-07-21T10:35:40.000Z"}]},
{id:112,title:"another",path:"4",readMessages:[],unreadMessages:[{id:8,text:"tux",InsertDate:"2020-07-21T10:35:40.000Z"}]},
{id:113,title:"another",path:"5",readMessages:[],unreadMessages:[{id:2,text:"tux",InsertDate:"2020-07-20T10:35:40.000Z"},{id:2,text:"lux",InsertDate:"2020-07-21T10:35:40.000Z"}]}
];
const getLastMessage = item => {
const messages = [...item.readMessages, ...item.unreadMessages].sort((a, b) =>
a.InsertDate < b.InsertDate ? 1 : -1,
);
return messages[0];
};
const sortedItems = items.sort((a, b) => {
// (1) Amount of unreadMessages [desc]
if (a.unreadMessages.length > b.unreadMessages.length) {
return -1;
} else if (a.unreadMessages.length < b.unreadMessages.length) {
return 1;
}
// (2) Time passed since last message [desc]
const aLastMessage = getLastMessage(a);
const bLastMessage = getLastMessage(b);
// Checking the emptiness of one of the message arrays
if (aLastMessage && !bLastMessage) {
return -1;
} else if (!aLastMessage && bLastMessage) {
return 1;
}
if (aLastMessage.InsertDate > bLastMessage.InsertDate) {
return -1;
} else if (aLastMessage.InsertDate < bLastMessage.InsertDate) {
return 1;
}
// (3) Path [asc]
if (a.path > b.path) {
return 1;
} else if (a.path < b.path) {
return -1;
}
return 0;
});
console.log(
'Sorted ids:',
sortedItems.map(i => i.id),
);
console.log(sortedItems);
推荐阅读
- powershell - 如何比较 Powershell 中的版本号?
- foreach - 在 GeoDMS 中,cdf 似乎在 for_each 命令中不起作用
- java - 通过外键返回实例列表
- html - 如果用户已经完成表单只有提交按钮可以点击,提交按钮将链接到另一个页面
- android - 插入设备时如何使用 WorkManager 创建作业?
- android - Android Studio 二合一
- php - Laravel Nova 如何在文本字段中添加实时计数器
- office365 - BizTalk SharePoint 适配器和 SharePoint Online 更新 SharePoint 列表的权限
- xml - 如果属性存在于 xml 的 ref url 中,如何在 xslt 中选择条件?
- java - 使用 Gradle Kotlin DSL 包含脚本