[英]Sorting an array of objects -> if key comes later in the array, change order
假设我有这个对象数组:
let arrOfObjs = [
{
"id": "unique1",
"parentId": "unique3", // So this one is equal to arrOfObjs[2].id
"title": "title1"
},
{
"id": "unique2",
"parentId": "unique3", // This one is also equal to arrOfObjs[2].id
"title": "title2"
},
{
"id": "unique3",
"parentId": "",
"title": "title3"
}
]
情况是:
id 始终是唯一的
parentId 不是唯一的。 parentId 等于其中一个对象中的 id 之一
我想要达到的目标:
id 应该总是比数组中的 parentId 早。 在上面的示例中,前两个对象包含“unique3” (3d 对象的 ID)作为 parentId。 那不应该发生。
所以应该这样排序:
let arrOfObjs = [
{
"id": "unique3",
"parentId": "",
"title": "title3"
}
{
"id": "unique2",
"parentId": "unique3",
"title": "title2"
},
{
"id": "unique1",
"parentId": "unique3",
"title": "title1"
}
]
所以根据object的parentId,它应该找到与parentId相等的id,当object的索引更高时,该id应该是object。
有点难以解释,但我希望它很清楚,如果您有任何问题,请告诉我
还没有尝试过任何东西,不知道我怎么能做到这一点。
尝试这个:
arrOfObjs.sort((a, b) => {
let aIndex = arrOfObjs.findIndex(obj => obj.id === a.parentId);
let bIndex = arrOfObjs.findIndex(obj => obj.id === b.parentId);
return aIndex - bIndex;
});
您可以从最后开始 go 并检查前任是否包含父级并交换项目。
const sort = array => { let l = array.length, i = l; while (--i) { let j = i; while (j--) { if (array[j].parentId === array[i].id) { [array[i], array[j]] = [array[j], array[i]]; i = l; break; } } } return array; }; console.log(sort([{ id: "unique1", parentId: "unique3", title: "title1" }, { id: "unique2", parentId: "unique3", title: "title2" }, { id: "unique3", parentId: "", title: "title3" }])); console.log(sort([{ id: 4, parentId: 2 }, { id: 1, parentId: 3 }, { id: 2, parentId: 3 }, { id: 3, parentId: 0 }]));
.as-console-wrapper { max-height: 100%;important: top; 0; }
我首先想到的是,您只需要移动数组顶部没有父项的所有项。 在这种情况下,所有“父母”都在使用前声明。
我们可以通过排序 function 来实现:
arrOfObjs.sort(({ parentId: a }, { parentId: b }) => {
if (a === '')
return -1;
if (b === '')
return 1;
return 0;
});
然后我意识到某些“父项”可能是其他项的父项。 因此,排序 function 不能满足我们的要求。
接下来是解决方案。 如果在数组的先行切片中没有id
等于其parentId
的项目,我们将遍历数组并将项目移动到尾部。
诀窍是在循环中即时修改数组。 不确定时间复杂度,也许是 θ(n^2)。
for (let i = 0, [item] = arrOfObjs; i < arrOfObjs.length; item = arrOfObjs[++i]) {
if (item.parentId !== '' && arrOfObjs.slice(0, i).every(x => x.id !== item.parentId)) {
arrOfObjs.push(arrOfObjs.splice(i--, 1)[0]);
}
}
请注意,两个项目的交叉链接会导致无限循环
我们可以将您的对象数组解释为图形。 对象是顶点,非空的parentId表示顶点与边相连。
当且仅当它们代表一个森林时,对象的排序是可能的——如果图中有一个循环,则没有排序(循环除外——顶点连接到自身),如果没有循环,我们就有一个森林.
算法应该从数组创建一个森林,然后以 BFS 顺序遍历所有树,将顶点推送到结果数组。 如果 BFS 两次访问某个顶点,则表示存在循环。
我认为这在 O(n) 复杂度中应该是可行的。 稍后我会尝试包含一些代码。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.