我有以下对象结构
layout: [
{
type: "FOLDER",
id: "folder0",
children: [
{
type: "FILE",
id: "file0",
},
{
type: "FOLDER",
id: "folder00",
children: [
{
type: "FILE",
id: "file7",
}
]
},
{
type: "FOLDER",
id: "folder02",
children: [
{
type: "FILE",
id: "file8",
}
]
}
]
},
{
type: "FOLDER",
id: "folder2",
children: [
{
type: "FILE",
id: "file4",
}
]
},
{
type: "FOLDER",
id: "folder1",
children: [
{
type: "FILE",
id: "file2",
},
{
type: "FILE",
id: "file3",
}
]
},
{
type: "FILE",
id: "file6",
}
]我使用下面的代码添加/删除/移动我从这个例子获取的内容
export const remove = (arr, index) => [
// part of the array before the specified index
...arr.slice(0, index),
// part of the array after the specified index
...arr.slice(index + 1)
];
export const removeChildFromChildren = (children, splitItemPath) => {
if (splitItemPath.length === 1) {
const itemIndex = Number(splitItemPath[0]);
return remove(children, itemIndex);
}
const updatedChildren = [...children];
const curIndex = Number(splitItemPath.slice(0, 1));
// Update the specific node's children
const splitItemChildrenPath = splitItemPath.slice(1);
const nodeChildren = updatedChildren[curIndex];
updatedChildren[curIndex] = {
...nodeChildren,
children: removeChildFromChildren(
nodeChildren.children,
splitItemChildrenPath
)
};
return updatedChildren;
};
export const insert = (arr, index, newItem) => {
console.log("insideinsert", arr, index, newItem)
return [
// part of the array before the specified index
...arr.slice(0, index),
// inserted item
newItem,
// part of the array after the specified index
...arr.slice(index)
];
}
export const addChildToChildren = (children, splitDropZonePath, item, targetid) => {
if (splitDropZonePath.length === 1) {
const dropZoneIndex = Number(splitDropZonePath[0]);
return insert(children, dropZoneIndex, item);
}
const updatedChildren = [...children];
const curIndex = Number(splitDropZonePath.slice(0, 1));
const splitItemChildrenPath = splitDropZonePath.slice(1);
const nodeChildren = updatedChildren[curIndex];
updatedChildren[curIndex] = {
...nodeChildren,
children: addChildToChildren(
nodeChildren.children,
splitItemChildrenPath,
item
)
};
return updatedChildren;
};
export const handleMoveToDifferentParent = (
layout,
splitDropZonePath,
splitItemPath,
item,
targetid
) => {
const removedfromlayout = removeChildFromChildren(layout, splitItemPath);
return addChildToChildren(
removedfromlayout,
splitDropZonePath,
item,
targetid
);
};handleMoveToDifferentParent(layout, [0,2], [0,0], file0inobjectform)但是当我用索引路径调用它时。它将file0移动到folder02而不是folder00,有更简单的方法吗?我不确定如何插入by id,因为索引数组也决定顺序数组。
发布于 2022-01-17 00:37:51
给定不变的助手splice(a, k, trans),其中-
a是输入数组k是要更新的关键(索引)trans是一个在k接收元素并返回替换值的函数。trans(a[k])的新数组,该数组位于k位置。未修改输入a。// splice :: ('a array, int, 'a -> 'a) -> 'a array
function splice(a, k, trans) {
return a.slice(0, k).concat(trans(a[k])).concat(a.slice(k + 1))
}以及不变的助手extract(t, path)在这里-
t是来自树的{ id, type, children? }形状的节点。path是一个索引数组。[selected, tprime],其中selected是path末尾的节点,tprime是一个新树,从树中删除selected。输入树t不发生变异。此实现特别注意只遵循有效的索引路径。当extract试图获得FILE的后代时,或者当node.type既不是FOLDER也不是FILE时,会抛出一个错误-
// extract :: ('a tree, int array) -> ('a, 'a tree)
function extract(t, path) {
function loop(t, [i, ...path], cont) {
if (i == null)
return cont(t, _ => [])
else switch (t?.type) {
case "FOLDER":
return loop(t.children[i], path, (selected, trans) =>
cont(selected, a => ({ ...a, children: splice(a.children, i, trans) }))
)
case "FILE":
throw Error(`cannot get descendant of file: ${JSON.stringify(t)}`)
default:
throw Error(`unsupported type: ${JSON.stringify(t)}`)
}
}
return path.length == 0
? [undefined, t]
: loop(t, path, (selected, trans) => [selected, trans(t)])
}给定一个输入树mytree,注意添加了一个root节点,所以最多只有一个根节点-
const mytree = {
id: "root",
type: "FOLDER",
children: [
{
id: "foo",
type: "FOLDER",
children: [
{ id: "foo1", type: "FILE" },
{ id: "foo2", type: "FILE" }
]
},
{
id: "bar",
type: "FOLDER",
children: [
{ id: "bar1", type: "FILE" }
]
}
]
}让我们按照下面的索引提取foo2,[0,1]
const [selected, tprime] = extract(mytree, [0,1])
console.log("selected", selected)
console.log("new tree", tprime)selected {
id: "foo2",
type: "FILE"
}
new tree {
id: "root",
type: "FOLDER",
children: [
{
id: "foo",
type: "FOLDER",
children: [
{ id: "foo1", type: "FILE" }
]
},
{
id: "bar",
type: "FOLDER",
children: [
{ id: "bar1", type: "FILE" }
]
}
]
}我们可以通过选择bar来提取所有的[1]
const [selected, tprime] = extract(mytree, [1])
console.log("selected", selected)
console.log("new tree", tprime)selected {
id: "bar",
type: "FOLDER",
children: [
{ id: "bar1", type: "FILE" }
]
}
new tree {
id: "root",
type: "FOLDER",
children: [
{
id: "foo",
type: "FOLDER",
children: [
{ id: "foo1", type: "FILE" },
{ id: "foo2", type: "FILE" }
]
}
]
}在26行代码中,我们已经解决了一半以上的问题。节点插入要容易得多,并留作读者练习-
function insert(t, path, node) {
//...
}
function move(t, srcPath, destPath) {
const [selectedNode, newTree] = extract(t, srcPath)
return insert(newTree, destPath, selectedNode)
}为了完整演示本文中的代码,请展开下面的代码片段,并在您自己的浏览器中验证结果-
function splice(a, k, trans) {
return a.slice(0, k).concat(trans(a[k])).concat(a.slice(k + 1))
}
function extract(t, path) {
function loop(t, [i, ...path], cont) {
if (i == null)
return cont(t, _ => [])
else switch (t?.type) {
case "FOLDER":
return loop(t.children[i], path, (selected, trans) =>
cont(selected, a => ({ ...a, children: splice(a.children, i, trans) }))
)
case "FILE":
throw Error(`cannot get descendant of file: ${JSON.stringify(t)}`)
default:
throw Error(`unsupported type: ${JSON.stringify(t)}`)
}
}
return path.length == 0
? [undefined, t]
: loop(t, path, (selected, trans) => [selected, trans(t)])
}
const t =
{ id: "root", type: "FOLDER", children: [
{ id: "foo", type: "FOLDER", children: [
{ id: "foo1", type: "FILE" },
{ id: "foo2", type: "FILE" }
]},
{ id: "bar", type: "FOLDER", children: [
{ id: "bar1", type: "FILE" }
]}
]}
const [selected, tprime] = extract(t, [0,0])
console.log("selected", selected)
console.log("new tree", tprime)
https://stackoverflow.com/questions/70731014
复制相似问题