【问题标题】:Moving an object in a recursive array在递归数组中移动对象
【发布时间】:2020-10-15 11:37:39
【问题描述】:

我正在开发一个 vue js 应用程序,我有以下递归数组:

[
        {
            id: 1,
            name: "sam",
            list: [
                {
                    id: 2,
                    name: "john",
                    list: []
                },
                {
                    id: 6,
                    name: "sarah",
                    list: [
                        {
                            id: 21,
                            name: "fadi",
                            list: []
                        }
                    ]
                }
            ]
        },
        {
            id: 3,
            name: "ross",
            list: [
                {
                    id: 4,
                    name: "maya",
                    list: []
                }
            ]
        },
        {
            id: 5,
            name: "steph",
            list: []
        },
        {
            id: 7,
            name: "joseph",
            list: []
        },
    ],

所以我有需要移动的对象的 id 和应该移动的位置的 id 例如我得到 idmoving=6 和 destination = 2 所以 id 6 的对象及其内容应该移动到列表id 为 2 的对象列表如下:

    [
        {
            id: 1,
            name: "sam",
            list: [
                {
                    id: 2,
                    name: "john",
                    list: [
                {
                    id: 6,
                    name: "sarah",
                    list: [
                        {
                            id: 21,
                            name: "fadi",
                            list: []
                        }
                    ]
                }
            ]
                },
            ]
        },
        {
            id: 3,
            name: "ross",
            list: [
                {
                    id: 4,
                    name: "maya",
                    list: []
                }
            ]
        },
        {
            id: 5,
            name: "steph",
            list: []
        },
        {
            id: 7,
            name: "joseph",
            list: []
        },
    ],

对不起,我还是新手,我希望有人可以提供可以做到这一点的功能。

【问题讨论】:

    标签: javascript arrays vue.js sorting recursion


    【解决方案1】:

    可以提前获取想要的节点和目标对象的源数组和索引,拼接数组,将拼接后的数组推送到目标数组。

    这种方法采用深度优先搜索,如果找到两个节点,则退出递归。

    const
        move = (data, from, to) => {
            const
                search = array => array.some((o, index) => {
                    if (o.id === from) source = { array, index };
                    else if (o.id === to) target = o;
                    return source && target || search(o.list);
                });
            let source, target;
    
            if (!search(data)) return;
            target.list.push(...source.array.splice(source.index, 1));
        },
        data = [{ id: 1, name: "sam", list: [{ id: 2, name: "john", list: [] }, { id: 6, name: "sarah", list: [{ id: 21, name: "fadi", list: [] }] }] }, { id: 3, name: "ross", list: [{ id: 4, name: "maya", list: [] }] }, { id: 5, name: "steph", list: [] }, { id: 7, name: "joseph", list: [] }];
    
    move(data, 6, 2);
           
    console.log(data);
    .as-console-wrapper { max-height: 100% !important; top: 0; }

    【讨论】:

    • 这是最好的命令式形式。一个真正的灵感,尼娜
    【解决方案2】:

    我可能会在一些可重用的辅助函数上写这个。移动一个值就是在一个位置找到它,从那里删除它,然后将它添加到一个新位置。所以我会编写一个move 函数,它使用findremoveadd 函数。

    每个都可以通过一些相当简单的递归来完成。这是一种方法:

    // Helper functions
    const findById = (id, xs) => 
      xs .reduce (
        (r, x) => r != null ? r : x.id == id ? x : findById (id, x .list) || null,
        null
      )
    
    const removeById = (id, xs) =>
      xs .reduce (
        (r, x) => x.id === id ? r : [... r, {... x, list: removeById (id, x .list)}], 
        [] 
      )
    
    const addById = (id, newVal, xs) =>
      xs .reduce (
        (r, x) => [... r, {... x, list: [... addById (id, newVal, x .list), ... (x.id == id ? [newVal] : [])]}],
        []
      )
    
    // Main function
    const moveById = (id, toId, data) => 
      addById (toId, findById (id, data), removeById (id, data))
    
    
    // Sample data
    const data = 
      [{id: 1, list: [{id: 2, list: [], name: "john"}, {id: 6, list: [{id: 21, list: [], name: "fadi"}], name: "sarah"}], name: "sam"}, {id: 3, list: [{id: 4, list: [], name: "maya"}], name: "ross"}, {id: 5, list: [], name: "steph"}, {id: 7, list: [], name: "joseph"}]
    
    // Demo
    console .log (moveById (6, 2, data))
    .as-console-wrapper {max-height: 100% !important; top : 0}

    这还不完整。据推测,在我们尝试添加某个值之前,需要对是否找到某个值进行某种错误检查。

    我实际上会以更通用的方式编写这些帮助程序,使用任意谓词而不是 id 作为输入。如果它们被柯里化了,那么我们可以通过将应用 id 值的结果传递给像(id) => (x) => x.id == id 这样的函数来创建谓词来轻松创建findById。所以在实践中,我可能会写一些更像:

    const recursiveFind = (pred) => (xs) => 
      xs .reduce (
        (r, x) => r != null ? r : pred (x) ? x : recursiveFind (pred) (x .list || []) || null,
        null
      )
    
    const findById = (id) => 
      recursiveFind (x => x.id === id)
    

    removeadd 也有类似的东西。

    这些对recursiveRemove ((x) => x.id > 5) (data) 很有用,它会删除任何嵌套级别的所有 id 大于 5 的元素。

    我可能会更进一步使您的list 属性可参数化。但是您可以在 another SO answer 中看到这种方法。

    【讨论】:

    • 我们得到了四个更小的可重用函数,而不是一个庞然大物的函数:D
    猜你喜欢
    • 2015-02-19
    • 2016-11-03
    • 2011-06-14
    • 1970-01-01
    • 1970-01-01
    • 2015-10-07
    • 2016-07-26
    • 2020-08-04
    • 1970-01-01
    相关资源
    最近更新 更多