JavaScript如何按指定块大小/重复模式对对象数组自定义排序
特定分块排序实现方案
核心规则拆解
你要的排序逻辑本质是以Reference为分块基准,而非原始数组的索引,之前的实现错误点在于直接对原始数组按长度切分,没有对齐分块维度:
- 分块对象是预排序后的去重Reference列表,不是原始数据条目
- 每个Reference块内,按Step从小到大遍历取数
- 前一个Reference块的所有Step条目全部取完,再处理下一个Reference块
以示例数据、chunk size=3为例,排序逻辑走查:
- 去重后有序Reference列表为
['AA08','AA09','AA10','AA11'],切分后得到两个Reference块:['AA08','AA09','AA10']、['AA11'] - 处理第一个Reference块:
- 取Step=1的三个条目:AA08-1、AA09-1、AA10-1
- 取Step=2的三个条目:AA08-2、AA09-2、AA10-2
- 取Step=3的三个条目:AA08-3、AA09-3、AA10-3
- 处理第二个Reference块:
- 取Step=1的条目:AA11-1
- 取Step=2的条目:AA11-2
- 取Step=3的条目:AA11-3
输出结果完全匹配你给出的期望顺序。
实现步骤
- 提取有序去重Reference列表:遍历原始数据,按首次出现顺序收集Reference,保留原始数据预排序的Reference优先级(不需要重新按日期等规则排序)
- 切分Reference块:按设定的chunk size,把有序Reference列表切成多个子组
- 构建查找索引:以
Reference-Step为键存储原始条目,避免后续取数时重复遍历数组 - 按规则组装结果:遍历每个Reference块,块内按Step从小到大遍历,依次取出块内每个Reference对应当前Step的条目,按顺序塞入结果数组
可运行代码示例
const chunkSize = 3; // 替换为实际从数据库查询返回的JSON数据 const jsonData = [ { Reference: 'AA08', Date: '2022-06-22', Step: 1 }, { Reference: 'AA09', Date: '2022-06-23', Step: 1 }, { Reference: 'AA10', Date: '2022-06-24', Step: 1 }, { Reference: 'AA11', Date: '2022-06-24', Step: 1 }, { Reference: 'AA08', Date: '2022-06-22', Step: 2 }, { Reference: 'AA09', Date: '2022-06-23', Step: 2 }, { Reference: 'AA10', Date: '2022-06-24', Step: 2 }, { Reference: 'AA11', Date: '2022-06-24', Step: 2 }, { Reference: 'AA08', Date: '2022-06-22', Step: 3 }, { Reference: 'AA09', Date: '2022-06-23', Step: 3 }, { Reference: 'AA10', Date: '2022-06-24', Step: 3 }, { Reference: 'AA11', Date: '2022-06-24', Step: 3 } ]; // 1. 提取有序去重Reference列表 const orderedReferences = []; const seenRefs = new Set(); for (const item of jsonData) { if (!seenRefs.has(item.Reference)) { seenRefs.add(item.Reference); orderedReferences.push(item.Reference); } } // 2. 切分Reference块 const refChunks = []; for (let i = 0; i < orderedReferences.length; i += chunkSize) { refChunks.push(orderedReferences.slice(i, i + chunkSize)); } // 3. 构建条目查找索引 const itemIndex = new Map(); for (const item of jsonData) { const key = `${item.Reference}-${item.Step}`; itemIndex.set(key, item); } // 4. 组装最终排序结果 const processedData = []; // 提取所有Step值并升序排列 const allSteps = [...new Set(jsonData.map(item => item.Step))].sort((a, b) => a - b); for (const chunk of refChunks) { for (const step of allSteps) { for (const ref of chunk) { const targetItem = itemIndex.get(`${ref}-${step}`); if (targetItem) { processedData.push({ ...targetItem, FullId: `${ref}-${step}` // 按需保留拼接后的完整标识字段 }); } } } } console.log(processedData);
原有代码问题说明
之前的实现直接对原始数组按索引做固定长度切分,而原始数据本身是按Step聚簇排列(所有Step=1条目在前,之后是Step=2、Step=3条目),切分后会把AA11-1划入第一个数据块,最终得到第一种不符合要求的排序结果,核心是分块的基准对象选错了。
内容的提问来源于stack exchange,提问作者Ben in CA
相关产品推荐
相关产品推荐

