Javascript算法-按日期列出的消息部分列表 介绍
我从数据库中获取消息(使用双向分页(最新消息在底部,旧消息在顶部),因此每次获取15条消息时,我都将它们划分到各自的日期组中 我有点卡住了,因为如果你想获得好的性能,算法有点复杂 代码 这是我目前的代码:Javascript算法-按日期列出的消息部分列表 介绍,javascript,algorithm,performance,optimization,ecmascript-6,Javascript,Algorithm,Performance,Optimization,Ecmascript 6,我从数据库中获取消息(使用双向分页(最新消息在底部,旧消息在顶部),因此每次获取15条消息时,我都将它们划分到各自的日期组中 我有点卡住了,因为如果你想获得好的性能,算法有点复杂 代码 这是我目前的代码: export default class MessagesDatesSectioner { constructor( dateOptions = { weekday: "short", year: "numeric",
export default class MessagesDatesSectioner {
constructor(
dateOptions = {
weekday: "short",
year: "numeric",
month: "short",
day: "numeric",
}
) {
this.dateOptions = dateOptions;
this.sections = [];
this.sectionsRef = new Map();
}
/**
* Group a list of messages by date, generating a list of sections
* which contains a title (the messages day as string), and an array
* of data that contains all the messages.
*
* @param {list of objects} messages [{ date, text }, ...].
*/
sectionizeMessagesByDate(messages) {
let sections = messages.reduce((sections, message) => {
const key =
message.date
.toDate?.()
.toLocaleDateString(undefined, this.dateOptions) ||
message.date.toLocaleDateString(undefined, this.dateOptions);
if (!sections[key]) {
sections[key] = [];
}
sections[key].push(message);
return sections;
}, {});
sections = Object.keys(sections).map((key) => ({
title: key,
data: sections[key],
}));
// Merge the resulted sections with the existed ones
this.mergeNewMessagesSections(sections);
}
/**
* Get a list of new sections (or groups of messages), and merge them
* with the existing sections.
*
* @param {list of objects} newMessagesSections [{ title: "Monday", data: [{date, text}, ...], }, ...].
*/
mergeNewMessagesSections(newMessagesSections) {
for (const { title, data } of newMessagesSections) {
if (!this.sectionsRef.has(title)) {
this.sectionsRef.set(title, this.sections.length);
this.sections.push({ title, data: [] });
}
this.sections[this.sectionsRef.get(title)].data.push(...data);
}
}
deleteMessage(message) {
// TODO
}
// Return a copy of the sections list
getSections() {
return [...this.sections];
}
}
问题
我的问题出现在向这些结构添加数据时。由于我使用双向分页,新消息的日期可能早于或晚于先前分段的消息
例如:
1- Call sectionizeMessagesByDate() with the following messages
[
{ date: new Date("10/31/2000 00:00:01"), text: "Hello" },
{ date: new Date("10/31/2001 00:00:02"), text: "World" },
] // Note: All messages are sorted by date in the given array by default (Do not care about it)
2- When merging, as there is no data in the sections list, it will generate the following:
[
{
title: "10/31/2000",
data: [ { date: new Date("10/31/2000 00:00:01"), text: "Hello" } ]
},
{
title: "10/31/2001", // Other year (different date)
data: [ { date: new Date("10/31/2000 00:00:02"), text: "Hello" } ]
}
]
如您所见,合并时,新节将添加到当前节列表的尾部
因此,如果类生成一个日期为“10/31/1999”的新节,它将添加到底部,而不保留日期顺序
如何实现节和节消息(在数据数组中)之间的排序(按日期),以保持良好的性能
注意:映射“sectionsRef”将节的标题作为键,并在节列表中作为值进行索引,只是为了在将消息插入现有节时实现O(1)复杂度顺序。这是我能想到的最好的方法 (未实现,我已经编写了伪代码) 有很多假设,但我想你说的是典型的WhatsApp聊天 为了对节和消息进行排序,您还必须添加一个“firstMessageDate”字段(在伪称为“date”的字段中),该字段必须是JS日期对象,因为您无法按如下方式构建它们:
const date = new Date("Monday"); // Invalid date
以下是我的意大利面算法:
mergeNewMessagesSections(newMessagesSections) {
for (const { title, data } of newMessagesSections) {
// If the section doesnt exist...
if (!this.sectionsRef.has(title)) {
// 1. Insert the section at the head or at the tail of the existing sections list?
// if (section.date > sections[0].date)
// insert the older section at the head of the existing sections list
// Also, reorder (recalculate) the sectionsRef indices and add it to the head of the map
// else
// insert the newer section at the tail of the existing sections list
// No map reordering required, just insert the section at the end of the refs map
//
//
//
// Note:
// In the typical chat screens, the top section of messages is always older than the middle section of messages
// In the other hand, the bottom section of messages is always newer then the middle ones.
this.sections.push({ title, data: [] });
this.sectionsRef.set(title, this.sections.length);
}
// 2. Insert the messages at the head or at the tail of the existing section?
// if (section.date >= sections[this.sectionsRef.get(title)].data[0])
// insert the old messages at the head of the section
// else
// insert the most fresh messages at the tail of the section
//
//
// Note: (as happen with sections)
// In chat screens, the top messages are always older than the middle messages.
// In the other hand, the bottom messages are always newer than the middle ones.
//
this.sections[this.sectionsRef.get(title)].data.push(...data);
}
}
您通常会对多少项进行排序?@jarmod此算法用于聊天屏幕(取决于用户滚动)。在每个滚动结束时(或由于双向性而到达顶部),用户从数据库中获得15条新消息(按日期排序)。这15条消息直接传递给此类(MessagesDataSectioner.sectionizeMessagesByDate(消息列表))。