繁体   English   中英

对对象数组进行排序 -> 如果键出现在数组的后面,则更改顺序

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM