基于字符串列表排序对象列表的JavaScript实现问题
问题描述
现有对象列表listA:
const listA = [ { name: 'John', visible: true }, { name: 'Andy', visible: false }, { name: 'Oliver', visible: true }, { name: 'Freddy', visible: true }, ];
需要依据字符串列表listB对listA进行排序:
const listB = ['Oliver', 'John', 'Freddy'];
特殊规则:listA中未出现在listB里的元素(比如示例中的Andy),需要保留其在listA中的原始位置。期望输出结果:
const listC = [ { name: 'Oliver', visible: true }, { name: 'Andy', visible: false }, { name: 'John', visible: true }, { name: 'Freddy', visible: true }, ];
原代码将所有在listB中的元素排完序后放在前面,不在的放在后面,无法满足需求,需要修正。
解决方案
以下是满足需求的实现代码:
const listA = [ { name: 'John', visible: true }, { name: 'Andy', visible: false }, { name: 'Oliver', visible: true }, { name: 'Freddy', visible: true }, ]; const listB = ['Oliver', 'John', 'Freddy']; function sortByList(arrayA, arrayB) { // 创建listB的映射表,提升查找效率 const nameOrderMap = new Map(arrayB.map((name, index) => [name, index])); // 提取arrayA中属于listB的元素,并按listB顺序排序 const sortedTargetItems = arrayA .filter(item => nameOrderMap.has(item.name)) .sort((a, b) => nameOrderMap.get(a.name) - nameOrderMap.get(b.name)); // 创建迭代器,按顺序取出排序后的元素 const sortedIterator = sortedTargetItems[Symbol.iterator](); let nextSortedItem = sortedIterator.next(); // 遍历原数组构建结果 return arrayA.map(item => { if (!nameOrderMap.has(item.name)) { // 不在listB的元素,直接保留原位置 return item; } else { // 取出排序队列中的下一个元素填充当前位置 const current = nextSortedItem.value; nextSortedItem = sortedIterator.next(); return current; } }); } // 获取排序结果 const listC = sortByList(listA, listB); // 渲染结果到页面 const result = document.getElementById('app'); listC.forEach((item) => { const listItem = document.createElement('li'); listItem.textContent = item.name; result.appendChild(listItem); });
代码解释
- 映射表优化:用
Map存储listB中每个名字对应的排序索引,避免多次调用indexOf带来的性能损耗,数组规模越大优势越明显。 - 目标元素排序:过滤出
listA中属于listB的元素,通过映射表的索引值排序,得到符合listB顺序的元素队列。 - 原位置保留逻辑:遍历原数组时,非目标元素直接保留;目标元素则从排序队列中按顺序取出填充,既保证了排序规则,又维持了非目标元素的原始位置。
内容的提问来源于stack exchange,提问作者userdac
相关产品推荐
相关产品推荐

