如何使用索引数组来导航对象数组
How can I use an array of indexes to nagivate an array of objects
我正在制作清单应用程序,需要浏览我的数据以编辑 complete:false
我的数据结构中子项是可选键,具有子项的对象不会有完整的键。
我有两种方法可以解决这个问题
- 使用
path
的每个部分并使用 items[path[0]]
等导航数组
- 或将
path
用作(或替换为)唯一的 id
并搜索该 ID
这两个我都不知道怎么做
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] }],
},
],
},
]
有没有办法在所有子键和 return 项中递归(或不搜索)搜索特定的 path/id 以便对其进行修改?
也许这样的事情可以让你开始:
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]
1。关注 path
这是更直接的方法,因为我们可以直接去找到想要的元素。因此,这可能会更高效。
这是一种方法:
- 浏览所有必要的
.children
s。
- 取
path
中最后一个索引指定的元素。
1.导航 .children
s:
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。按最后一个索引取元素:
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]];
}
我们实际上还没有考虑 edge-cases,即:
- 如果
data
(或此处的任何数组)是空数组怎么办?
- 如果给定路径上的元素没有
.children
怎么办?
这里有一个解决方法:
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);
2。按 path
(作为 ID)
查找
理想情况下,我们将所有元素放在一个平面数组中,因为这样我们就可以简单地进行 Array.find()
搜索。
因为我们最初获取的是tree-like结构中的元素,所以我们必须手动将它们展平。这是一种方法:
const _flatten = (el) => ([el, ...(el.children ?? []).flatMap(_flatten)]);
const flatten = (array) => array.flatMap(_flatten);
现在我们有了所有元素的平面数组,我们可以使用 Array.find()
:
function findChild(path, treeElements) {
// When equal, serializes to the same string
const isEqual = (p1, p2) => p1.join() === p2.join();
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) {
// When equal, serializes to the same string
const isEqual = (p1, p2) => p1.join() === p2.join();
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);
1和2的比较
根据 JSBen.ch,与预期相比,第一个选项比第二个选项快大约 4-5 倍。
我正在制作清单应用程序,需要浏览我的数据以编辑 complete:false
我的数据结构中子项是可选键,具有子项的对象不会有完整的键。
我有两种方法可以解决这个问题
- 使用
path
的每个部分并使用items[path[0]]
等导航数组 - 或将
path
用作(或替换为)唯一的id
并搜索该 ID
这两个我都不知道怎么做
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] }],
},
],
},
]
有没有办法在所有子键和 return 项中递归(或不搜索)搜索特定的 path/id 以便对其进行修改?
也许这样的事情可以让你开始:
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]
1。关注 path
这是更直接的方法,因为我们可以直接去找到想要的元素。因此,这可能会更高效。
这是一种方法:
- 浏览所有必要的
.children
s。 - 取
path
中最后一个索引指定的元素。
1.导航 .children
s:
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。按最后一个索引取元素:
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]];
}
我们实际上还没有考虑 edge-cases,即:
- 如果
data
(或此处的任何数组)是空数组怎么办? - 如果给定路径上的元素没有
.children
怎么办?
这里有一个解决方法:
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);
2。按 path
(作为 ID)
查找
理想情况下,我们将所有元素放在一个平面数组中,因为这样我们就可以简单地进行 Array.find()
搜索。
因为我们最初获取的是tree-like结构中的元素,所以我们必须手动将它们展平。这是一种方法:
const _flatten = (el) => ([el, ...(el.children ?? []).flatMap(_flatten)]);
const flatten = (array) => array.flatMap(_flatten);
现在我们有了所有元素的平面数组,我们可以使用 Array.find()
:
function findChild(path, treeElements) {
// When equal, serializes to the same string
const isEqual = (p1, p2) => p1.join() === p2.join();
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) {
// When equal, serializes to the same string
const isEqual = (p1, p2) => p1.join() === p2.join();
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);
1和2的比较
根据 JSBen.ch,与预期相比,第一个选项比第二个选项快大约 4-5 倍。