我正在寻找一种方法将这个递归对象数组转换为平面对象数组,以便更容易使用。
[
{
"name": "bill",
"car": "jaguar",
"age": 30,
"profiles": [
{
"name": "stacey",
"car": "lambo",
"age": 23,
"profiles": [
{
"name": "martin",
"car": "lexus",
"age": 34,
"profiles": []
}
]
}
]
}
]
这是预期的输出。
[
{
"name": "bill",
"car": "jaguar",
"age": 30,
},{
"name": "stacey",
"car": "lambo",
"age": 23,
},{
"name": "martin",
"car": "lexus",
"age": 34,
}
]
每个profiles
数组可以包含n
个项目,这些项目可能有也可能没有子profiles
的空数组。请注意,转换后的转换后的数组对象不包含profiles
。
我愿意使用underscore
或lodash
来实现此目标。
答案 0 :(得分:3)
让我们调用您的原始数据o
,将Array.prototype.reduce与递归相结合,我想出了这个:
o.reduce(function recur(accumulator, curr) {
var keys = Object.keys(curr);
keys.splice(keys.indexOf('profiles'), 1);
accumulator.push(keys.reduce(function (entry, key) {
entry[key] = curr[key];
return entry;
}, {}));
if (curr.profiles.length) {
return accumulator.concat(curr.profiles.reduce(recur, []));
}
return accumulator;
}, []);
答案 1 :(得分:1)
我会使用递归函数并将结果数组传递给它,以避免使用全局变量,这些内容符合以下几行:
var target = [];
var extractElements(source, target) {
//TODO: check if source is array
for (var i=0; i<source.length; i++) {
// create a new element with our data
var newElement = {
name: source[i].name,
car: source[i].car,
age: source[i].age
};
// put it in our flattened array
target.push(newElement);
// check if we need to go deeper and pass our flattened array around
if (source[i].profiles instanceof Array &&
source[i].profiles.length>0)
extractElements(source[i].profiles, target);
}
}
console.log(target) // should list your elements nicely
我还没有测试过,所以请用它来获取灵感,但要注意:)
(edit1:“var i”in for)
答案 2 :(得分:1)
const _ = require('lodash')
const arrayFromObject = (currentObject, currentArray) => {
const {profiles, ...rest} = currentObject
if (!_.isEmpty(currentObject.profiles)) {
return arrayFromObject(currentObject.profiles!, [...currentArray, rest])
}
return [...currentArray, rest]
}
const flatArray = arrayFromObject(myRecursiveObject, [])
答案 3 :(得分:0)
嗨,这也可以尝试......
var out = [];
var i=0;
var extract = function(s, out) {
if(s[0] == null){
i = out.length -1;
return false;
}else {
out.push(s[0]);
}
extract(s[0].profiles, out);
delete out[i--].profiles;
};
extract(a, out); /// here 'a' is the input array and 'out' output
console.log(out);
一切顺利......
答案 4 :(得分:0)
var _ = require('lodash')
/**
* Flatten a array-object via recursive property
* @see {@link http://stackoverflow.com/questions/31829897/convert-recursive-array-object-to-flat-array-object}
* @param {Array} arr Array of objects with recursive props
* @param {String} recursiveProperty The string of the recursive property
* @return {Array} Flat array of all recursive properties without recursive property
*/
function arrExtract (arr, recursiveProperty) {
var extracted = []
function _arrExtract (children) {
_.each(children, function (item) {
if (item[recursiveProperty] && item[recursiveProperty].length) _arrExtract(item[recursiveProperty])
extracted.push(_.omit(item, recursiveProperty))
})
}
_arrExtract(arr)
return extracted
}
module.exports = arrExtract
答案 5 :(得分:0)
差不多三年后,仍然在寻找一种适合这种情况的单一尺寸解决方案。在这里,受@ axelduch的回答影响很大。
const {isPlainObject, isArray, get, omit, reduce} = require('lodash')
const recursiveFlatten = (tree, headProp, parentIdProp, parentRefProp, parent = {}) => {
tree = isArray(tree) ? tree : [tree]
return reduce(tree, (acq, current) => {
const currentWithoutHead = omit(current, [headProp])
if (parentIdProp && parentRefProp) currentWithoutHead[parentRefProp] = parent[parentIdProp] || null
acq = [...acq, currentWithoutHead]
const next = get(current, headProp)
if (isPlainObject(next) || isArray(next)) {
parent = currentWithoutHead
acq = [...acq, ...recursiveFlatten(next, headProp, parentIdProp, parentRefProp, parent)]
}
return acq
}, [])
}
这是一个简单的例子:
const example = recursiveFlatten({
name: 'bill',
love: true,
lovers: [{
name: 'jil',
love: false,
lovers: [{
name: 'diana',
love: false,
lovers: false
}, {
name: 'einstein',
love: false,
lovers: {
name: 'carl sagan',
love: false,
lovers: false
}
}]
}]
}, 'lovers')
[ { name: 'bill', love: true },
{ name: 'jil', love: false },
{ name: 'diana', love: false },
{ name: 'einstein', love: false },
{ name: 'carl sagan', love: false } ]
以下是通过parentId
添加parentRef
道具的示例。
const example = recursiveFlatten({
name: 'bill',
love: true,
lovers: [{
name: 'jil',
love: false,
lovers: [{
name: 'diana',
love: false,
lovers: false
}, {
name: 'einstein',
love: false,
lovers: {
name: 'carl sagan',
love: false,
lovers: false
}
}]
}]
}, 'lovers', 'name', 'parentName')
[ { name: 'bill', love: true, parentName: null },
{ name: 'jil', love: false, parentName: 'bill' },
{ name: 'diana', love: false, parentName: 'jil' },
{ name: 'einstein', love: false, parentName: 'jil' },
{ name: 'carl sagan', love: false, parentName: 'einstein' } ]
答案 6 :(得分:0)
这是一种相当简单的技术,可以解决最初定义的问题。
const recursiveFlatten = (tree) =>
tree .length == 0
? []
: tree .flatMap (({profiles = [], ... rest}) => [{... rest}, ... recursiveFlatten (profiles)])
const tree = [{name: "bill", car: "jaguar", age: 30, profiles: [{name: "stacey", car: "lambo", age: 23, profiles: [{name: "martin", car: "lexus", age: 34, profiles: []}]}]}, {name: "denise", car: "pinto", age: 28}]
console .log (
recursiveFlatten (tree)
)
这会将名称“配置文件”硬编码并删除,从而使其余属性在生成的副本中保持完整。
您自己的回答表明要复杂得多的要求。此版本通过几个可选参数来处理这些问题,就像您的答案一样,尽管此处称呼的方式已更改,并且在必要时可以轻松更改:
const recursiveFlatten = (headProp, parentIdProp, parentRefProp, parent = {}) => (tree) =>
tree .length == 0
? []
: tree .flatMap (({[headProp]: children = [], ... rest}) => [
{
... rest,
... (parentIdProp && parentRefProp ? {[parentRefProp]: parent[parentIdProp] || null} : {})
},
... recursiveFlatten (headProp, parentIdProp, parentRefProp, rest) (children)
])
const tree = [{name: "bill", car: "jaguar", age: 30, profiles: [{name: "stacey", car: "lambo", age: 23, profiles: [{name: "martin", car: "lexus", age: 34, profiles: []}]}]}, {name: "denise", car: "pinto", age: 28}]
console .log (recursiveFlatten ('profiles') (tree))
console .log (recursiveFlatten ('profiles', 'name', 'parentName') (tree))
不过,我不会在自己的代码库中对此API感到兴奋。取决于传递多少参数的不同行为会增加不必要的复杂性。我可能会将它们埋在
之类的API下const recursiveFlatten = (parentIdProp, parentRefProp) => (headProp) => (tree) => ...
然后我们可以创建所需的功能,例如使用
const flattenProfiles = recursiveFlatten (null, null) ('profiles')
和
const flattenAndExpand = recuriveFlatten ('name', 'parentName') ('profiles')
替换上面console .log ()
语句中的两个调用。