【问题标题】:How can i dynamically reduce deep JS objects with arrays to a JS object without arrays in javascript?如何在javascript中动态地将带有数组的深层JS对象减少为没有数组的JS对象?
【发布时间】:2019-05-22 02:30:13
【问题描述】:

我有一个对象数组,每个对象都有一个 id 作为键。每个对象代表 id 的导航列表。

我需要将所有导航列表合并到一个大列表中,其中叶子包含所属的 id。

生成的对象应该不包含数组,而是包含将成为 id 列表的叶子。

我已经尝试过递归解决方案,lodash 函数,如合并和分配,但我坚持对象的深度

输入的 JSON 例如:

[
  {
    "id0": [
      {
        "Topitem 1": [
          {
            "Subitem 1": [
              "Leaf 1"
            ]
          }, {
            "Subitem 2": [
              "Leaf 2"
            ]
          }
        ]
      },
      {
        "Topitem 1": [
          {
            "Subitem 3": [
              "Leaf 1"
            ]
          }
        ]
      },
      {
        "Topitem 2": [
          "Leaf 1",
          "Leaf 3"
        ]
      },
      {
        "Topitem 3": [
          {
            "Subitem 1": [
              {
                "SubSubitem 1": [
                  "Leaf 4"
                ]
              }
            ]
          }
        ]
      }
    ]
  },
  {
    "id1": [
      "Leaf 5"
    ]
  },
  {
    "id2": [
      "Leaf 5"
    ]
  },
  {
    "id3": [
      {
        "Topitem 1": [
          "Leaf 1",
          {
            "Subitem 2": [
              "Leaf 2",
              "Leaf 3"
            ]
          }
        ]
      }, {
        "Topitem 2": [
          "Leaf 1",
          "Leaf 2"
        ]
      }
    ]
  },
  {
    "id4": [
      "Leaf 5"
    ]
  }
]

预期的输出是:

{
  "Topitem 1": {
    "Subitem 1": {
      "Leaf 1": ["id0"]
    },
    "Subitem 2": {
      "Leaf 2": ["id0","id3"],
      "Leaf 3": ["id3"]
    },
    "Subitem 3": {
      "Leaf 1": ["id0"]
    },
    "Leaf 1": ["id3"]
  },
  "Topitem 2": {
    "Leaf 1": ["id0","id3"],
    "Leaf 2": ["id0","id3"]
  },
  "Topitem 3": {
    "Subitem 1": {
      "SubSubitem 1": {
        "Leaf 4": ["id0"]
      }
    }
  },
  "Leaf5": ["id1","id2","id4"]
}

【问题讨论】:

    标签: javascript arrays json object merge


    【解决方案1】:

    您可以通过在第一次运行时使用不同的函数来采用迭代和递归方法,在其中保存 id 以供以后收集到数组中,然后将递归部分用于嵌套对象/键。

    给定数据结构的主要问题是,数组最后包含字符串而不是对象。

    function convert(array) {
    
        function iter(array, object, value) {
            array.forEach(o => {
                if (!o || typeof o !== 'object') {
                    (object[o] = object[o] || []).push(value);
                    return;
                }
                Object
                    .entries(o)
                    .forEach(([k, v]) => iter(v, object[k] = object[k] || {}, value));
            });
        }
    
        var result = {};
        array.forEach(o => Object.entries(o).forEach(([k, v]) => iter(v, result, k)));
        return result;
    }
    
    var data = [{ id0: [{ "Topitem 1": [{ "Subitem 1": ["Leaf 1"] }, { "Subitem 2": ["Leaf 2"] }] }, { "Topitem 1": [{ "Subitem 3": ["Leaf 1"] }] }, { "Topitem 2": ["Leaf 1", "Leaf 3"] }, { "Topitem 3": [{ "Subitem 1": [{ "SubSubitem 1": ["Leaf 4"] }] }] }] }, { id1: ["Leaf 5"] }, { id2: ["Leaf 5"] }, { id3: [{ "Topitem 1": ["Leaf 1", { "Subitem 2": ["Leaf 2", "Leaf 3"] }] }, { "Topitem 2": ["Leaf 1", "Leaf 2"] }] }, { id4: ["Leaf 5"] }];
    
    console.log(convert(data));
    .as-console-wrapper { max-height: 100% !important; top: 0; }

    【讨论】:

      【解决方案2】:

      这是使用lodashobject-scan 的解决方案。此解决方案无需递归即可工作

      // const objectScan = require('object-scan');
      // const lodash = require('lodash');
      
      const myObject = [{ id0: [{ 'Topitem 1': [{ 'Subitem 1': ['Leaf 1'] }, { 'Subitem 2': ['Leaf 2'] }] }, { 'Topitem 1': [{ 'Subitem 3': ['Leaf 1'] }] }, { 'Topitem 2': ['Leaf 1', 'Leaf 3'] }, { 'Topitem 3': [{ 'Subitem 1': [{ 'SubSubitem 1': ['Leaf 4'] }] }] }] }, { id1: ['Leaf 5'] }, { id2: ['Leaf 5'] }, { id3: [{ 'Topitem 1': ['Leaf 1', { 'Subitem 2': ['Leaf 2', 'Leaf 3'] }] }, { 'Topitem 2': ['Leaf 1', 'Leaf 2'] }] }, { id4: ['Leaf 5'] }];
      
      const convert = (obj) => objectScan(['**'], {
        filterFn: ({ key, value, context }) => {
          if (typeof value !== 'string') {
            return;
          }
          const k = [...key.slice(2).filter((e) => typeof e === 'string'), value];
          const cur = lodash.get(context, k);
          if (cur === undefined) {
            lodash.set(context, k, [key[1]]);
          } else {
            cur.push(key[1]);
          }
        }
      })(obj, {});
      
      console.log(convert(myObject));
      // => { 'Leaf 5': [ 'id4', 'id2', 'id1' ], 'Topitem 2': { 'Leaf 2': [ 'id3' ], 'Leaf 1': [ 'id3', 'id0' ], 'Leaf 3': [ 'id0' ] }, 'Topitem 1': { 'Subitem 2': { 'Leaf 3': [ 'id3' ], 'Leaf 2': [ 'id3', 'id0' ] }, 'Leaf 1': [ 'id3' ], 'Subitem 3': { 'Leaf 1': [ 'id0' ] }, 'Subitem 1': { 'Leaf 1': [ 'id0' ] } }, 'Topitem 3': { 'Subitem 1': { 'SubSubitem 1': { 'Leaf 4': [ 'id0' ] } } } }
      .as-console-wrapper {max-height: 100% !important; top: 0}
      <script src="https://bundle.run/object-scan@13.7.1"></script>
      <script src="https://bundle.run/lodash@4.17.20"></script>

      免责声明:我是object-scan的作者

      这是一个解决方案,我们跟踪堆栈,因此避免使用 lodash。不幸的是,它并不像我希望的那样优雅

      // const objectScan = require('object-scan');
      
      const myObject = [{ id0: [{ 'Topitem 1': [{ 'Subitem 1': ['Leaf 1'] }, { 'Subitem 2': ['Leaf 2'] }] }, { 'Topitem 1': [{ 'Subitem 3': ['Leaf 1'] }] }, { 'Topitem 2': ['Leaf 1', 'Leaf 3'] }, { 'Topitem 3': [{ 'Subitem 1': [{ 'SubSubitem 1': ['Leaf 4'] }] }] }] }, { id1: ['Leaf 5'] }, { id2: ['Leaf 5'] }, { id3: [{ 'Topitem 1': ['Leaf 1', { 'Subitem 2': ['Leaf 2', 'Leaf 3'] }] }, { 'Topitem 2': ['Leaf 1', 'Leaf 2'] }] }, { id4: ['Leaf 5'] }];
      
      const convert = (obj) => objectScan(['[*]*.**[*]', '[*]*.**.*'], {
        breakFn: ({
          matchedBy, key, value, property, context
        }) => {
          if (matchedBy.includes('[*]*.**.*')) {
            const cur = context[context.length - 1];
            if (!(property in cur)) {
              cur[property] = {};
            }
            context.push(cur[property]);
          } else if (typeof value === 'string') {
            const cur = context[context.length - 1];
            if (!(value in cur)) {
              cur[value] = [];
            }
            cur[value].push(key[1]);
          }
        },
        filterFn: ({ matchedBy, context }) => {
          if (matchedBy.includes('[*]*.**.*')) {
            context.pop();
          }
        }
      })(obj, [{}])[0];
      
      console.log(convert(myObject));
      // => { 'Leaf 5': [ 'id4', 'id2', 'id1' ], 'Topitem 2': { 'Leaf 2': [ 'id3' ], 'Leaf 1': [ 'id3', 'id0' ], 'Leaf 3': [ 'id0' ] }, 'Topitem 1': { 'Subitem 2': { 'Leaf 3': [ 'id3' ], 'Leaf 2': [ 'id3', 'id0' ] }, 'Leaf 1': [ 'id3' ], 'Subitem 3': { 'Leaf 1': [ 'id0' ] }, 'Subitem 1': { 'Leaf 1': [ 'id0' ] } }, 'Topitem 3': { 'Subitem 1': { 'SubSubitem 1': { 'Leaf 4': [ 'id0' ] } } } }
      .as-console-wrapper {max-height: 100% !important; top: 0}
      &lt;script src="https://bundle.run/object-scan@13.7.1"&gt;&lt;/script&gt;

      免责声明:我是object-scan的作者

      【讨论】:

        猜你喜欢
        • 2017-10-02
        • 2018-05-30
        • 1970-01-01
        • 2021-03-24
        • 2021-04-02
        • 2018-09-01
        • 1970-01-01
        • 2017-12-08
        相关资源
        最近更新 更多