JS如何高效将对象数组按id分区块,实现区块及内部时间戳升降序排序
问题分析
你的现有实现是将不同id的区块按id字符串的字典序排序,没有用到「区块首元素timestamp」作为区块排序的判定依据,因此不符合需求。
可行实现方案
可以先分组、再组内排序、再按组基准排序、最后展开,逻辑更清晰也更容易维护,适合大型数组的场景:
function sortElements(elements, sortAscending = true) { // 1. 按id分组 const groups = {} elements.forEach(item => { if (!groups[item.id]) groups[item.id] = [] groups[item.id].push(item) }) // 2. 每个组内部先按timestamp排序,得到组首元素的基准timestamp Object.values(groups).forEach(group => { group.sort((a, b) => { return sortAscending ? a.timestamp - b.timestamp : b.timestamp - a.timestamp }) }) // 3. 把所有组按组首的timestamp排序 const sortedGroups = Object.values(groups).sort((groupA, groupB) => { const baseA = groupA[0].timestamp const baseB = groupB[0].timestamp return sortAscending ? baseA - baseB : baseB - baseA }) // 4. 扁平化得到最终结果 return sortedGroups.flat() }
调用示例
// 升序排序 const sortedAsc = sortElements(elements, true) // 降序排序 const sortedDesc = sortElements(elements, false)
如果你的数组体量特别大,不想额外占用分组的内存空间,也可以先预计算每个id对应的基准timestamp存到Map里,再直接用原生sort实现:
function sortElementsInPlace(elements, sortAscending = true) { // 预计算每个id的基准timestamp(即该id下对应排序规则的首个元素timestamp) const idBaseMap = new Map() elements.forEach(item => { if (!idBaseMap.has(item.id)) { idBaseMap.set(item.id, item.timestamp) return } const currentBase = idBaseMap.get(item.id) if (sortAscending) { if (item.timestamp < currentBase) idBaseMap.set(item.id, item.timestamp) } else { if (item.timestamp > currentBase) idBaseMap.set(item.id, item.timestamp) } }) elements.sort((a, b) => { // 先按组基准排序 const baseA = idBaseMap.get(a.id) const baseB = idBaseMap.get(b.id) if (baseA !== baseB) { return sortAscending ? baseA - baseB : baseB - baseA } // 同组内按timestamp排序 return sortAscending ? a.timestamp - b.timestamp : b.timestamp - a.timestamp }) return elements }
内容的提问来源于stack exchange,提问作者Raphael
相关产品推荐
相关产品推荐

