
在前端开发中,我们经常会遇到需要根据特定逻辑对数据数组进行重排的需求。一个常见的场景是处理具有父子关系的数据结构,其中每个元素可能包含一个id和一个reference_id(或parent_id),reference_id指向其父元素的id。我们的目标是将所有子元素紧跟在它们的父元素之后,即使父元素本身没有reference_id(即它是顶级元素)。
考虑以下数据结构:
const initialArray = [
{ id: 1, name: 'hello world', reference_id: null },
{ id: 2, name: 'hello world', reference_id: null },
{ id: 3, name: 'hello world', reference_id: 1 },
{ id: 4, name: 'hello world', reference_id: null },
{ id: 5, name: 'hello world', reference_id: 1 },
{ id: 6, name: 'hello world', reference_id: 2 },
];我们期望的排序结果是:
[
{ id: 1, name: 'hello world', reference_id: null },
{ id: 3, name: 'hello world', reference_id: 1 },
{ id: 5, name: 'hello world', reference_id: 1 },
{ id: 2, name: 'hello world', reference_id: null },
{ id: 6, name: 'hello world', reference_id: 2 },
{ id: 4, name: 'hello world', reference_id: null },
]可以看到,id: 3和id: 5(它们的reference_id都是1)被排在了id: 1之后;id: 6(reference_id是2)被排在了id: 2之后。
直接使用 findIndex 和 splice 等方法来动态修改数组通常会导致复杂且难以维护的代码,尤其是在循环中修改数组长度和索引时,容易产生“意外结果”或逻辑错误。更推荐的做法是利用数组的 sort 方法,结合自定义的比较函数。
立即学习“Java免费学习笔记(深入)”;
这种方法的核心思想是:首先为每个元素创建一个临时的排序键,然后根据这个键进行排序,最后移除这个临时键,还原为原始对象。
const arr = [
{ id: 1, name: 'hello world', reference_id: null },
{ id: 2, name: 'hello world', reference_id: null },
{ id: 3, name: 'hello world', reference_id: 1 },
{ id: 4, name: 'hello world', reference_id: null },
{ id: 5, name: 'hello world', reference_id: 1 },
{ id: 6, name: 'hello world', reference_id: 2 },
];
const sortedResult = arr
.map(item => ({
// 构建排序键:将 reference_id 视为父ID,如果为 null 则视为空字符串,
// 然后拼接当前 id。这样,父元素(reference_id为null)的键会以其id开头,
// 子元素(reference_id为父id)的键会以父id开头。
// 例如:
// id: 1, ref: null -> "1"
// id: 3, ref: 1 -> "13"
// id: 5, ref: 1 -> "15"
// id: 2, ref: null -> "2"
// id: 6, ref: 2 -> "26"
sortKey: `${item.reference_id ?? ''}${item.id}`,
originalElement: item,
}))
.sort((a, b) => a.sortKey.localeCompare(b.sortKey)) // 使用 localeCompare 进行字符串比较
.map(item => item.originalElement); // 还原原始对象
console.log(sortedResult);为了避免创建中间对象,我们可以直接在 sort 方法的比较函数中动态生成排序键。这种方法更高效,但比较函数的逻辑可能略显复杂。
const arr = [
{ id: 1, name: 'hello world', reference_id: null },
{ id: 2, name: 'hello world', reference_id: null },
{ id: 3, name: 'hello world', reference_id: 1 },
{ id: 4, name: 'hello world', reference_id: null },
{ id: 5, name: 'hello world', reference_id: 1 },
{ id: 6, name: 'hello world', reference_id: 2 },
];
// 定义一个函数来生成元素的排序标准字符串
const getSortCriterion = (item) => {
// 1. 处理 reference_id:如果为 null,则视为空字符串。
// 2. 使用 padStart(4, "0") 确保数字字符串长度一致,防止 "10" < "2" 的错误比较。
// 例如:id=1 -> "0001", id=10 -> "0010"
// 3. 使用 "|" 作为分隔符,确保 reference_id 和 id 的组合不会混淆。
// 例如:ref=1, id=2 -> "0001|0002"
// ref=12, id=3 -> "0012|0003"
const refIdString = ("" + (item.reference_id ?? "")).padStart(4, "0");
const idString = ("" + item.id).padStart(4, "0");
return `${refIdString}|${idString}`;
};
// 对数组进行排序
const sortedResult = [...arr].sort((a, b) =>
getSortCriterion(a).localeCompare(getSortCriterion(b))
);
console.log(sortedResult);
console.log("计算出的排序标准(用于调试):");
console.log(sortedResult.map(getSortCriterion));通过构建自定义的排序键,我们可以有效地解决根据 id 和 reference_id 对数组进行复杂重排序的问题。无论是采用两步映射和排序的清晰方法,还是单次排序与自定义比较函数的更高效方法,关键都在于设计一个能够准确反映期望顺序的比较逻辑。在实际开发中,根据项目需求和数据规模选择最合适的方案,并始终注意保持代码的不可变性和可维护性。
以上就是JavaScript/React中根据ID和引用ID实现复杂数组重排序教程的详细内容,更多请关注php中文网其它相关文章!
每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号