[英]How can I use an array of indexes to nagivate an array of objects
I'm making a checklist app and need to navigate through my data to edit the complete:false
我正在制作一个清单应用程序,需要浏览我的数据以编辑complete:false
My data is structured with children being an optional key, and objects with children won't have the completed key.我的数据结构中,children 是一个可选的键,而有children 的对象没有完整的键。
There are two ways I could solve this有两种方法可以解决这个问题
path
and navigate the array using items[path[0]]
and so on使用path
的每个部分并使用items[path[0]]
等导航数组path
as (or replace it with) a unique id
and search for that id或使用path
作为(或替换为)唯一id
并搜索该IDboth of which I do not know how to do这两个我都不知道该怎么做
const TESTDATA = [
{
name: 'foo',
path: [0],
open: true,
children: [
{ name: 'bar', completed: false, path: [0, 0] },
{ name: 'data', completed: false, path: [0, 1] },
],
},
{
name: 'foo',
path: [1],
open: true,
children: [
{ name: 'bar', completed: false, path: [1, 0] },
{
name: 'data',
completed: false,
path: [1, 1],
children: [{ name: 'baz', completed: false, path: [1, 1, 0] }],
},
],
},
]
Is there a way to recursively (or not) search for a specific path/id in all the children keys and return the item so it could be modified?有没有办法递归(或不)在所有子键中搜索特定路径/ID并返回该项目以便对其进行修改?
maybe something like this can get you started:也许这样的事情可以让你开始:
function gather(name, obj){
if(name==obj.name) return obj;
if(obj.children) return obj.children.map(x=>gather(name, x)).flat().filter(Boolean)
}
TESTDATA.map(x=>gather("baz", x)).flat()[0]
path
1.跟随path
This is the more direct way, as we can literally go and find the wanted element.这是更直接的方法,因为我们可以从字面上找到想要的元素。 As such, this is likely more performant.因此,这可能更高效。
Here is one way to do it:这是一种方法:
.children
.浏览所有必要的.children
。path
.取path
中最后一个索引指定的元素。 1. Navigate .children
: 1. 导航.children
:
function findChild(path, data) {
let array = data;
for (let i = 0; i < path.length - 1; ++i) {
const pathIndex = path[i];
array = array[pathIndex].children;
}
// ...
}
2. Take element by last index: 2.按最后一个索引取元素:
function findChild(path, data) {
let array = data;
for (let i = 0; i < path.length - 1; ++i) {
const pathIndex = path[i];
array = array[pathIndex].children;
}
return array[path[path.length - 1]];
}
We actually haven't yet taken edge-cases into account, namely:我们实际上还没有考虑边缘情况,即:
data
(or any array here) is an empty array?如果data
(或此处的任何数组)是一个空数组怎么办?.children
?如果给定路径上的元素没有.children
怎么办?Here's a fix to that:这是一个修复:
function findChild(path, data) {
let array = data;
for (let i = 0; i < path.length - 1 && array; ++i) {
const pathIndex = path[i];
array = array[pathIndex]?.children;
}
return array?.[path[path.length - 1]];
}
function findChild(path, data) { let array = data; for (let i = 0; i < path.length - 1 && array; ++i) { const pathIndex = path[i]; array = array[pathIndex]?.children; } return array?.[path[path.length - 1]]; } const data = [ { name: 'foo', path: [0], open: true, children: [ { name: 'bar', completed: false, path: [0, 0] }, { name: 'data', completed: false, path: [0, 1] }, ], }, { name: 'foo', path: [1], open: true, children: [ { name: 'bar', completed: false, path: [1, 0] }, { name: 'data', completed: false, path: [1, 1], children: [{ name: 'baz', completed: false, path: [1, 1, 0] }], }, ], }, ]; console.time(); const result = findChild([1, 0], data); console.timeEnd(); console.log("Imperative:", result);
path
(as ID) 2.按path
查找(作为ID) Ideally we have all elements in a single, flat array, because then we can simply do a Array.find()
search.理想情况下,我们将所有元素放在一个单一的平面数组中,因为这样我们就可以简单地进行Array.find()
搜索。
Because we initially get the elements in a tree-like structure, we have to flatten them manually.因为我们最初以树状结构获取元素,所以我们必须手动将它们展平。 Here is one way to do that:这是一种方法:
const _flatten = (el) => ([el, ...(el.children ?? []).flatMap(_flatten)]);
const flatten = (array) => array.flatMap(_flatten);
Now that we have a flat array of all the elements, we can use Array.find()
:现在我们有了一个包含所有元素的平面数组,我们可以使用Array.find()
:
function findChild(path, treeElements) {
const isEqual = (a1, a2) => {
if (a1.length !== a2.length) return false;
return a1.every((v, i) => v === a2[i]);
};
const _flatten = (el) => ([el, ...(el.children ?? []).flatMap(_flatten)]);
const flatten = (array) => array.flatMap(_flatten);
return flatten(treeElements).find(el => isEqual(el.path, path));
}
function findChild(path, treeElements) { const isEqual = (a1, a2) => { if (a1.length !== a2.length) return false; return a1.every((v, i) => v === a2[i]); }; const _flatten = (el) => ([el, ...(el.children ?? []).flatMap(_flatten)]); const flatten = (array) => array.flatMap(_flatten); return flatten(treeElements).find(el => isEqual(el.path, path)); } const data = [ { name: 'foo', path: [0], open: true, children: [ { name: 'bar', completed: false, path: [0, 0] }, { name: 'data', completed: false, path: [0, 1] }, ], }, { name: 'foo', path: [1], open: true, children: [ { name: 'bar', completed: false, path: [1, 0] }, { name: 'data', completed: false, path: [1, 1], children: [{ name: 'baz', completed: false, path: [1, 1, 0] }], }, ], }, ]; console.time(); const result = findChild([1, 0], data); console.timeEnd(); console.log("Functional:", result);
As per JSBen.ch , the first option compared to the second option is about 3-4 times faster, as expected.根据JSBen.ch ,与第二个选项相比,第一个选项快了大约 3-4 倍,正如预期的那样。
(The implementation for the isEqual()
function is the quickest as per this benchmark .) (根据这个基准, isEqual()
函数的实现是最快的。)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.