代码之家  ›  专栏  ›  技术社区  ›  drip

以字符串形式输出对象树

  •  1
  • drip  · 技术社区  · 7 年前

    我在做一个小项目,我在特定的点上绊倒了。最疯狂的是,它看起来很简单,但我已经打我的头超过一个小时了。

    我有一个示例对象,例如:

    {
      l1_1: {
        l2_1: {
          l3_1: 'l1_1_l2_1_l3_1',
          l3_2: 'l1_1_l2_1_l3_2'
        },
        l2_2: {
          l3_1: 'l1_1_l2_2_l3_1',
          l3_2: 'l1_1_l2_2_l3_2'
        },
        l2_3: {
          l3_1: 'l1_1_l2_3_l3_1',
          l3_2: 'l1_1_l2_3_l3_2'
        }
      },
      l1_2: {
        l2_1: 'l1_2.l2_1',
        l2_2: 'l1_2.l2_2'
      }
    }
    

    我需要将每个路径输出到对象最深的子对象,如下所示(作为单独的字符串):

    l1_1.l2_1.l3_1
    l1_1.l2_1.l3_2
    l1_1.l2_2.l3_1
    l1_1.l2_2.l3_2
    l1_1.l2_3.l3_1
    l1_1.l2_3.l3_2
    l1_2.l2_1
    l1_2.l2_2
    

    问题是,对象对于每个子对象可能没有相同的deepnest。就像提供的例子一样可能有2级、3级、4级甚至5级)

    我的想法是,我将使用这些字符串来检查对象是否在特定的liquid文件中使用,其中它们使用以下语法 {{ 'l1_1.l2_1.l3_1' | t }}

    这是我在这一点上得出的结论。

    const obj = {
      l1_1: {
        l2_1: {
          l3_1: 'l1_1_l2_1_l3_1',
          l3_2: 'l1_1_l2_1_l3_2'
        },
        l2_2: {
          l3_1: 'l1_1_l2_2_l3_1',
          l3_2: 'l1_1_l2_2_l3_2'
        },
        l2_3: {
          l3_1: 'l1_1_l2_2_l3_1',
          l3_2: 'l1_1_l2_2_l3_2'
        }
      },
      l1_2: {
        l2_1: 'l1_2.l2_1',
        l2_2: 'l1_2.l2_2'
      }
    }
    
    function iter(obj, keyTarget){
      Object.keys(obj).forEach(function(key) {
        const val = obj[key];
        if(typeof val == 'object'){
          keyTarget = keyTarget ? `${keyTarget}.${key}` : key;
          iter(val, keyTarget)
        } else {
          keyTarget = `${keyTarget}.${key}`;
          console.log(keyTarget)
        }
      });
    }
    
    iter(obj, false)

    我知道为什么代码不起作用,因为循环在同一个对象上多次传递,值在它们之间传递和共享,我得到了错误的值,但我无法找到一个解决方法,我可以清除字符串,同时将其保留给下一个对象。

    任何见解都将不胜感激。

    2 回复  |  直到 7 年前
        1
  •  5
  •   Nina Scholz    7 年前

    您可以收集路径,如果找到叶,则将此路径添加到结果集中。

    function getPathes(object, path = []) {
        return Object
            .entries(object)
            .reduce((r, [k, v]) => r.concat(!v || typeof v !== 'object'
                ? path.concat(k).join('.')
                : getPathes(v, path.concat(k))),
                []
            );
    }
    
    var data = { l1_1: { l2_1: { l3_1: 'l1_1_l2_1_l3_1', l3_2: 'l1_1_l2_1_l3_2' }, l2_2: { l3_1: 'l1_1_l2_2_l3_1', l3_2: 'l1_1_l2_2_l3_2' }, l2_3: { l3_1: 'l1_1_l2_3_l3_1', l3_2: 'l1_1_l2_3_l3_2' } }, l1_2: { l2_1: 'l1_2.l2_1', l2_2: 'l1_2.l2_2' } },
        pathes = getPathes(data);
        
    console.log(pathes);
    .as-console-wrapper { max-height: 100% !important; top: 0; }

    function getPathes(object, path = []) {
        return Object
            .entries(object)
            .reduce(
                (r, [k, v]) => r.concat(v && typeof v === 'object'
                    ? getPathes(v).map(v => k + '.' + v)
                    : v
                ),
                []
            );
    }
    
    var data = { l1_1: { l2_1: { l3_1: 'l1_1_l2_1_l3_1', l3_2: 'l1_1_l2_1_l3_2' }, l2_2: { l3_1: 'l1_1_l2_2_l3_1', l3_2: 'l1_1_l2_2_l3_2' }, l2_3: { l3_1: 'l1_1_l2_3_l3_1', l3_2: 'l1_1_l2_3_l3_2' } }, l1_2: { l2_1: 'l1_2.l2_1', l2_2: 'l1_2.l2_2' } },
        pathes = getPathes(data);
        
    console.log(pathes);
    。作为控制台包装{最大高度:100%!重要的;顶部:0;}
        2
  •  2
  •   Nenad Vracar    7 年前

    您可以使用 reduce 方法返回所有路径的数组。

    const data = {"l1_1":{"l2_1":{"l3_1":"l1_1_l2_1_l3_1","l3_2":"l1_1_l2_1_l3_2"},"l2_2":{"l3_1":"l1_1_l2_2_l3_1","l3_2":"l1_1_l2_2_l3_2"},"l2_3":{"l3_1":"l1_1_l2_3_l3_1","l3_2":"l1_1_l2_3_l3_2"}},"l1_2":{"l2_1":"l1_2.l2_1","l2_2":"l1_2.l2_2"}}
    
    function getPaths(data, prev = "") {
      return Object.entries(data).reduce((r, [k, v]) => {
        let path = prev + (prev.length ? '.' : '') + k
        if (typeof v == 'object') r = r.concat(getPaths(v, path))
        else r.push(path)
        return r;
      }, [])
    }
    
    const paths = getPaths(data)
    console.log(paths)