如何将嵌套的JavaScript对象转换为平面数组?

时间:2021-12-31 21:32:17

I've been coding at this solution for hours now and can't seem to make much progress anymore. It's a very difficult function to write. Here is my input:

我已经在这个解决方案上编写了几个小时的编码,似乎无法取得太大进展。这是一个非常难以写的功能。这是我的意见:

var testObj = {
  'b': 'num',
  'a': {
    'd': 'num',
    'c': 'num'
  },
  'g': ['num', 'num', {
    'x': 'num',
    'y': 'num'
  }],
  'e': 'num'
};

And here's the output I'm trying to generate from above:

这是我试图从上面生成的输出:

var flatTestObj = [
  ['b', 'num'],
  ['a', 'obj'],
  ['a', 'obj', 'd', 'num'],
  ['a', 'obj', 'c', 'num'],
  ['g', 'arr'],
  ['g', 'arr', 0, 'num'],
  ['g', 'arr', 1, 'num'],
  ['g', 'arr', 2, 'obj'],
  ['g', 'arr', 2, 'obj', 'x', 'num'],
  ['g', 'arr', 2, 'obj', 'y', 'num'],
  ['e', 'num']
];

(Later I'm going to alphabetize the keys too but I can handle that part on my own so I excluded that from the question to make it easier to answer) but yeah the point is to guarantee the same order traversal of objects of this format later on.

(后来我也要按字母顺序排列键,但我可以自己处理那个部分,所以我从问题中排除了这个以便更容易回答)但是,重点是保证这种格式的对象的顺序遍历相同稍后的。

Basically, have it recursively go through the object and add each key/index mapping as a new element to flatTestObj so later you can iterate through flatTestObj and get every member from testObj by referencing every other element from the current flatTestObj index array value.

基本上,让它以递归方式遍历对象并将每个键/索引映射作为新元素添加到flatTestObj,以便稍后您可以遍历flatTestObj并通过引用当前flatTestObj索引数组值中的每个其他元素从testObj获取每个成员。

Here's what I have so far but I'm having difficulty getting it to work with nesting:

这是我到目前为止所做的,但我很难让它与嵌套一起工作:

var flattened = [];

function flatten(json, acc) {
  var keys = Object.keys(json);

  for (var i = 0; i < keys.length; i++) {
    var key = keys[i];
    var val = json[key];

    var strVal = typeof val === 'object' ? 'obj' : val;

    if (acc.length === 0) {
      acc = [key, strVal];
    } else {
      acc = acc.concat([key, strVal]);
    }

    if (typeof val === 'object') {
      flatten(val, acc);
    } else {
      flattened.push(acc);
      acc = [];
    }
  }
}

flatten(testObj, []);

2 个解决方案

#1


1  

This gives the output you're looking for:

这给出了您正在寻找的输出:

var flattened = [];
function flatten(json, acc, inArray) {
  var key;

  acc = acc || [];
  for(key in json) {
    if(inArray) {
      key = +key;  //coerce to number
    }
    if(json[key] instanceof Array) {
      flattened.push(acc.concat([key, 'arr']));
      flatten(json[key], acc.concat([key, 'arr']), true);
    }
    else if(json[key] instanceof Object) {
      flattened.push(acc.concat([key, 'obj']));
      flatten(json[key], acc.concat([key, 'obj']));
    }
    else {
      flattened.push(acc.concat(key, json[key]));
    }
  }
} //flatten

Essentially, you need to include acc.concat() each time you push to the flattened array.

基本上,每次推送到扁平数组时都需要包含acc.concat()。

var testObj = {
  'b': 'num',
  'a': {
    'd': 'num',
    'c': 'num'
  },
  'g': ['num', 'num', {
    'x': 'num',
    'y': 'num'
  }],
  'e': 'num'
};

var flattened = [];
function flatten(json, acc, inArray) {
  var key;
  
  acc = acc || [];
  for(key in json) {
    if(inArray) {
      key = +key;  //coerce to number
    }
    if(json[key] instanceof Array) {
      flattened.push(acc.concat([key, 'arr']));
      flatten(json[key], acc.concat([key, 'arr']), true);
    }
    else if(json[key] instanceof Object) {
      flattened.push(acc.concat([key, 'obj']));
      flatten(json[key], acc.concat([key, 'obj']));
    }
    else {
      flattened.push(acc.concat(key, json[key]));
    }
  }
} //flatten

flatten(testObj);
console.log(JSON.stringify(flattened));

#2


1  

Here's one way to do it with recursive function calls

这是使用递归函数调用的一种方法

var testObj = {
    'b': 'num',
    'a': {
        'd': 'num',
        'c': 'num'
    },
    'g': ['num', 'num', {
        'x': 'num',
        'y': 'num'
    }],
    'e': 'num'
};

var flatTestObj = (function it(what, arr, chain) {
    if (typeof what === "object") {
        var fn = function(k) {
            var type = Array.isArray(what[k]) ? 'arr' : 'obj' ,
            	vArr = [k, typeof what[k] === "object" ? type : what[k]],
                fArr = chain.concat(vArr);
                            
            arr.push(fArr); 
            it(what[k], arr, fArr);
        }

    	if (Array.isArray(what)) for (var i in what) fn(i)
        else Object.keys(what).forEach(fn);
    }
    return arr;
})(testObj, [], []);

document.body.innerHTML = '<pre>' + JSON.stringify(flatTestObj, 0, 4) + '</pre>';

#1


1  

This gives the output you're looking for:

这给出了您正在寻找的输出:

var flattened = [];
function flatten(json, acc, inArray) {
  var key;

  acc = acc || [];
  for(key in json) {
    if(inArray) {
      key = +key;  //coerce to number
    }
    if(json[key] instanceof Array) {
      flattened.push(acc.concat([key, 'arr']));
      flatten(json[key], acc.concat([key, 'arr']), true);
    }
    else if(json[key] instanceof Object) {
      flattened.push(acc.concat([key, 'obj']));
      flatten(json[key], acc.concat([key, 'obj']));
    }
    else {
      flattened.push(acc.concat(key, json[key]));
    }
  }
} //flatten

Essentially, you need to include acc.concat() each time you push to the flattened array.

基本上,每次推送到扁平数组时都需要包含acc.concat()。

var testObj = {
  'b': 'num',
  'a': {
    'd': 'num',
    'c': 'num'
  },
  'g': ['num', 'num', {
    'x': 'num',
    'y': 'num'
  }],
  'e': 'num'
};

var flattened = [];
function flatten(json, acc, inArray) {
  var key;
  
  acc = acc || [];
  for(key in json) {
    if(inArray) {
      key = +key;  //coerce to number
    }
    if(json[key] instanceof Array) {
      flattened.push(acc.concat([key, 'arr']));
      flatten(json[key], acc.concat([key, 'arr']), true);
    }
    else if(json[key] instanceof Object) {
      flattened.push(acc.concat([key, 'obj']));
      flatten(json[key], acc.concat([key, 'obj']));
    }
    else {
      flattened.push(acc.concat(key, json[key]));
    }
  }
} //flatten

flatten(testObj);
console.log(JSON.stringify(flattened));

#2


1  

Here's one way to do it with recursive function calls

这是使用递归函数调用的一种方法

var testObj = {
    'b': 'num',
    'a': {
        'd': 'num',
        'c': 'num'
    },
    'g': ['num', 'num', {
        'x': 'num',
        'y': 'num'
    }],
    'e': 'num'
};

var flatTestObj = (function it(what, arr, chain) {
    if (typeof what === "object") {
        var fn = function(k) {
            var type = Array.isArray(what[k]) ? 'arr' : 'obj' ,
            	vArr = [k, typeof what[k] === "object" ? type : what[k]],
                fArr = chain.concat(vArr);
                            
            arr.push(fArr); 
            it(what[k], arr, fArr);
        }

    	if (Array.isArray(what)) for (var i in what) fn(i)
        else Object.keys(what).forEach(fn);
    }
    return arr;
})(testObj, [], []);

document.body.innerHTML = '<pre>' + JSON.stringify(flatTestObj, 0, 4) + '</pre>';