首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >递归函数将对象添加到深度嵌套的对象数组中,添加到错误的对象中。

递归函数将对象添加到深度嵌套的对象数组中,添加到错误的对象中。
EN

Stack Overflow用户
提问于 2022-01-16 14:31:28
回答 1查看 845关注 0票数 1

我有以下对象结构

代码语言:javascript
复制
    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",
        }


    ]

我使用下面的代码添加/删除/移动我从这个例子获取的内容

代码语言:javascript
复制
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
    );
};
代码语言:javascript
复制
handleMoveToDifferentParent(layout, [0,2], [0,0], file0inobjectform)

但是当我用索引路径调用它时。它将file0移动到folder02而不是folder00,有更简单的方法吗?我不确定如何插入by id,因为索引数组也决定顺序数组。

EN

回答 1

Stack Overflow用户

发布于 2022-01-17 00:37:51

给定不变的助手splice(a, k, trans),其中-

  • a是输入数组
  • k是要更新的关键(索引)
  • trans是一个在k接收元素并返回替换值的函数。
  • 返回一个插入trans(a[k])的新数组,该数组位于k位置。未修改输入a
代码语言:javascript
复制
// 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],其中selectedpath末尾的节点,tprime是一个新树,从树中删除selected。输入树t不发生变异。

此实现特别注意只遵循有效的索引路径。当extract试图获得FILE的后代时,或者当node.type既不是FOLDER也不是FILE时,会抛出一个错误-

代码语言:javascript
复制
// 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节点,所以最多只有一个根节点-

代码语言:javascript
复制
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]

代码语言:javascript
复制
const [selected, tprime] = extract(mytree, [0,1])
console.log("selected", selected)
console.log("new tree", tprime)
代码语言:javascript
复制
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]

代码语言:javascript
复制
const [selected, tprime] = extract(mytree, [1])
console.log("selected", selected)
console.log("new tree", tprime)
代码语言:javascript
复制
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行代码中,我们已经解决了一半以上的问题。节点插入要容易得多,并留作读者练习-

代码语言:javascript
复制
function insert(t, path, node) {
  //...
}

function move(t, srcPath, destPath) {
  const [selectedNode, newTree] = extract(t, srcPath)
  return insert(newTree, destPath, selectedNode)
}

为了完整演示本文中的代码,请展开下面的代码片段,并在您自己的浏览器中验证结果-

代码语言:javascript
复制
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)

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/70731014

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档