按首字母分组并将对象数组拆分至三列的均匀分布方案咨询
按首字母分组并均匀拆分到三列(带首字母标题)
问题背景
现有一个已按name排序的对象数组,结构如下:
let obj = { CategoryOne:[ { name: "An Item", color: "Red" }, { name: "Blue Item", color: "Blue" } ], CategoryTwo: [ // ... 更多项 ] // ... 更多分类 }
需要将每个分类下的数组按首字母拆分到三列,每列保留对应的首字母标题,同时尽量让三列的内容数量均匀分布。当前实现可运行,但无法做到首字母的均匀分布,且需保留首字母标题。
解决方案
步骤1:按首字母完整分组
先把每个分类下的所有项按首字母(大写)分组,确保同首字母的项不会被拆分到不同列:
function groupByFirstLetter(items) { return items.reduce((groups, item) => { const firstLetter = item.name[0].toUpperCase(); if (!groups[firstLetter]) { groups[firstLetter] = []; } groups[firstLetter].push(item); return groups; }, {}); }
步骤2:将首字母分组均匀分配到三列
把首字母分组按总数量加权,依次分配到当前项数最少的列,保证三列总内容量尽量均衡:
function distributeGroupsToColumns(groups) { // 转换分组格式,记录每个首字母分组的项数 const groupEntries = Object.entries(groups).map(([letter, items]) => ({ letter, items, count: items.length })); // 初始化三列结构,以及列项数跟踪器 const columns = [[], [], []]; const columnCounts = [0, 0, 0]; // 优先处理项数多的分组,避免大分组被拆分 groupEntries.sort((a, b) => b.count - a.count); groupEntries.forEach(group => { // 找到当前项数最少的列 const targetColIndex = columnCounts.indexOf(Math.min(...columnCounts)); columns[targetColIndex].push(group); columnCounts[targetColIndex] += group.count; }); // 将列转回{ 首字母: 项数组 }的格式,方便渲染 return columns.map(col => col.reduce((colObj, group) => { colObj[group.letter] = group.items; return colObj; }, {}) ); }
步骤3:整合处理所有分类
将上述两个函数结合,批量处理所有分类:
function sortIntoColumns(obj) { const sorted = {}; for (const key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { const category = obj[key]; const letterGroups = groupByFirstLetter(category); const [firstCol, secondCol, thirdCol] = distributeGroupsToColumns(letterGroups); sorted[key] = { firstCol, secondCol, thirdCol }; } } return sorted; }
关键说明
- 不拆分同首字母项:先完整分组再分配列,确保同一首字母的所有项都在同一列,完美匹配首字母标题的需求。
- 均匀分布:通过优先分配大分组到最短列的逻辑,保证三列的总项数尽量均衡,避免某一列过长。
- 渲染友好:最终输出结构与原代码一致,每个分类下的
firstCol/secondCol/thirdCol对象中,键就是首字母标题,值是对应项数组,可直接用于页面渲染。
内容的提问来源于stack exchange,提问作者DreadedSlug
相关产品推荐
相关产品推荐

