【问题标题】:Javascript - convert nested arrays into object of arraysJavascript - 将嵌套数组转换为数组对象
【发布时间】:2018-11-07 23:44:38
【问题描述】:

我有一个形状未知的嵌套数组。这是一个例子:

["head","val1","val2","val3",
    ["head2","val4","val5",
        ["head3","val6","val7", 
            ["head4", "val8"],"val9"]],
    ["head5", "val10", "val11"]
]

数组的长度都为 2 或更大。一个数组可以包含任意数量的其他数组,也可以包含任意数量的数组。所有值都是字符串或数组。

我正在尝试将其转换为具有以下形状的单个对象:

{"head": ["val1","val2","val3", 
    {"head2": ["val4","val5", 
        {"head3": ["val6","val7", 
            {"head4": ["val8"]}, "val9"]},
    {"head5": ["val10", "val11"]}
]}

基本上,每个数组都需要转换为一个对象,其中第一个值是键,数组的其余部分是值。 我试过使用reduce,但不能完全正确。

【问题讨论】:

  • 如果您展示了您的reduce 尝试,那就太好了,我们可以提供帮助
  • Array.prototype.shift+Array.isArray+recursion?

标签: javascript functional-programming lodash


【解决方案1】:

在这种情况下,您不知道嵌套数组的深度,因此最好设计一个递归函数。

在递归函数的基本情况下,输入不是数组,所以只需返回输入。

在输入为数组的情况下,创建一个具有单个属性的JS对象,其名称等于输入数组中的第一个元素,其值等于数组的其余部分...你需要针对每个剩余成员递归调用您的函数,以在结果数组中获取它们的值。

var a = ["head","val1","val2","val3",
    ["head2","val4","val5",
        ["head3","val6","val7", 
            ["head4", "val8"],"val9"]],
    ["head5", "val10", "val11"]
];

function convert(val) {
  var result;
  if (Array.isArray(val)) {
    var key = val[0];
    var vals = val.slice(1);
    result = {};
    result[key] = [];
    for (var i = 0; i < vals.length; i++) {
      result[key].push(convert(vals[i]));
    }
  } else {
    result = val;
  }
  return result;
}

console.log(convert(a));

【讨论】:

    【解决方案2】:

    像这样递归地做:

    function convert(arr) {
      return {
        [arr[0]]: arr.slice(1).map(item => Array.isArray(item)? convert(item): item)
      }
    }
    

    函数convert 返回一个包含一个键值对的对象。键是 arr[0],值是数组 (arr.slice(1)) 中映射到新数组的其余元素,以便在该数组内的所有数组元素上调用 convert

    ES5 版本:

    function convert(arr) {
      var obj = {};
      obj[arr[0]] = arr.slice(1).map(function(item) {
          return item instanceof Array? convert(item): item;
      });
      return obj;
    }

    示例:

    function convert(arr) {
      return {
        [arr[0]]: arr.slice(1).map(item => Array.isArray(item)? convert(item): item)
      }
    }
    
    let arr = ["head","val1","val2","val3",
        ["head2","val4","val5",
            ["head3","val6","val7", 
                ["head4", "val8"],"val9"]],
        ["head5", "val10", "val11"]
    ];
    
    let result = convert(arr);
    
    console.log(result);

    【讨论】:

    • 不确定 OP 选择正确答案的标准是什么,但我投票赞成您的解决方案。到目前为止,我的书中最干净的。如果您删除 return 并将 convert 函数转换为箭头符号,则可以使其更短...
    【解决方案3】:

    这样的?

    function convert(arr) {
      if (arr instanceof Array) {
        const [key, ...values] = arr;
        return { [key]: values.map(convert) };
      } else {
        return arr;
      }
    }
    
    const test = ["head","val1","val2","val3",
        ["head2","val4","val5",
            ["head3","val6","val7", 
                ["head4", "val8"],"val9"]],
        ["head5", "val10", "val11"]
    ];
    
    console.log(convert(test));

    【讨论】:

      【解决方案4】:

      ES6:您可以执行以下操作

      function convertArrayToObject(arr) {
        return Array.isArray(arr) && arr.length ? {
          [arr[0]]: arr.slice(1).map(convertArrayToObject)
        } : arr;
      }
      

      此代码定义了一个函数convertArrayToObject,如果它不是数组,则返回元素本身,或者将第一个元素设置为键,如果是数组,则将其余元素作为值调用该函数。

      【讨论】:

        【解决方案5】:

        这种有效的方法避免了使用slice()(这会创建一个大小为 N-1 的临时数组并被删除):

        function change(a) {
          let b = [];
          for (let i = 1; i < a.length; i++) {
            let v = a[i];
            b.push(Array.isArray(v) ? change(v) : v);
          }
          return {[a[0]]: b};
        }
        
        console.log(change(
          ["head","val1","val2","val3",
            ["head2","val4","val5",
                ["head3","val6","val7", 
                    ["head4", "val8"],"val9"]],
            ["head5", "val10", "val11"]
          ]
        ));

        【讨论】:

          【解决方案6】:

          既然你用lodash 标记了它,这里也有一个简短的解决方案:

          var data = ["head","val1","val2","val3", ["head2","val4","val5", ["head3","val6","val7", ["head4", "val8"],"val9"]], ["head5", "val10", "val11"] ]
          
          const f = (d) => ({[_.head(d)]: _.map(_.tail(d), x => _.isArray(x) ? f(x) : x)})
          
          console.log(f(data))
          &lt;script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.10/lodash.min.js"&gt;&lt;/script&gt;

          这是一种递归解决方案,它利用 lodash .head 获取数组的第一个元素,.tail 获取除第一个元素之外的所有元素,然后使用 _.map 遍历每个元素并返回一个数组。

          【讨论】:

            猜你喜欢
            • 2022-12-18
            • 1970-01-01
            • 1970-01-01
            • 2018-01-24
            • 2016-04-13
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2015-03-26
            相关资源
            最近更新 更多