Javascript-将嵌套数组转换为数组对象

时间:2018-11-07 23:44:38

标签: javascript functional-programming lodash

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

["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,但不太正确。

6 个答案:

答案 0 :(得分:3)

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

在递归函数的基本情况下,输入不是数组,因此只需返回输入即可。

在输入为数组的情况下,请创建一个具有单个属性的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));

答案 1 :(得分: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。 / p>

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);

答案 2 :(得分:1)

像这样吗?

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));

答案 3 :(得分:0)

ES6:您可以执行以下操作

export class SomeClass {

  // Navigate To
  constructor() {
      console.log("1. constructor")
  }

  canActivate() {
      console.log("2. canActivate")
  }

  activate() {
      console.log("3. activate")
  }

  attached() {
      // Page has loaded
      console.log("4. attached")
  }

  // Navigate Away
  canDeactivate() {
      console.log("1. canDeactivate")
  }

  deactivate() {
      console.log("2. deactivate")
  }

  detached() {
      console.log("3. detached")
  }
}

此代码定义了一个函数function convertArrayToObject(arr) { return Array.isArray(arr) && arr.length ? { [arr[0]]: arr.slice(1).map(convertArrayToObject) } : arr; } ,如果它不是数组,则返回元素本身,或者将第一个元素设置为键,如果是数组,则以其余元素作为值调用该函数。

答案 4 :(得分:0)

这种有效的方法避免使用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"]
  ]
));

答案 5 :(得分:0)

由于您用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))
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.10/lodash.min.js"></script>

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