I'm looking for a way to convert this array of recursive objects into a flat array of objects to make it easier to work with.
我正在寻找一种方法,将这个递归对象数组转换为一个平面对象数组,以便更容易使用。
[
{
"name": "bill",
"car": "jaguar",
"age": 30,
"profiles": [
{
"name": "stacey",
"car": "lambo",
"age": 23,
"profiles": [
{
"name": "martin",
"car": "lexus",
"age": 34,
"profiles": []
}
]
}
]
}
]
This is the expected output.
这是期望输出。
[
{
"name": "bill",
"car": "jaguar",
"age": 30,
},{
"name": "stacey",
"car": "lambo",
"age": 23,
},{
"name": "martin",
"car": "lexus",
"age": 34,
}
]
Each profiles
array can have n
amount of items, which may or may not have an empty array of sub profiles
. Note the converted array objects don't contain profiles
after the conversion.
每个配置文件数组可以有n个条目,这些条目可能有也可能没有一个空的子配置文件数组。注意,转换后的数组对象不包含配置文件。
I'm open to using underscore
or lodash
to achieve this.
我愿意使用下划线或破折号来实现这一点。
5 个解决方案
#1
3
Let's call your original data o
, combining Array.prototype.reduce with recursion I came up with this:
让我们调用原始数据o,结合Array.prototype。用递归来减少
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;
}, []);
#2
1
I would use a recursive function and pass the resulting array in it to avoid working with globals, something in the lines of:
我将使用递归函数并将结果数组传递给它,以避免使用全局变量,如下所示:
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
I haven't tested it, so use it for inspiration but beware :)
我还没有测试过,所以用它来激励自己,但要注意:
(edit1: "var i" in for)
(edit1: var i)
#3
0
Hi this can also be tried...
你好,这个也可以试试……
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);
All the best...
愿一切都好!
#4
0
var _ = require('lodash')
/**
* Flatten a array-object via recursive property
* @see {@link http://*.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
Almost three years later and still looking for a one-size fits solution for this. Here it is, heavily influenced by @axelduch's answer.
差不多三年过去了,但仍在寻找一种一刀切的解决方案。这是受到@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
}, [])
}
Here's a simple example:
这是一个简单的例子:
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 } ]
Here's an example adding parentId
prop via parentRef
.
这里有一个通过parentRef添加parentId支柱的例子。
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' } ]
#1
3
Let's call your original data o
, combining Array.prototype.reduce with recursion I came up with this:
让我们调用原始数据o,结合Array.prototype。用递归来减少
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;
}, []);
#2
1
I would use a recursive function and pass the resulting array in it to avoid working with globals, something in the lines of:
我将使用递归函数并将结果数组传递给它,以避免使用全局变量,如下所示:
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
I haven't tested it, so use it for inspiration but beware :)
我还没有测试过,所以用它来激励自己,但要注意:
(edit1: "var i" in for)
(edit1: var i)
#3
0
Hi this can also be tried...
你好,这个也可以试试……
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);
All the best...
愿一切都好!
#4
0
var _ = require('lodash')
/**
* Flatten a array-object via recursive property
* @see {@link http://*.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
Almost three years later and still looking for a one-size fits solution for this. Here it is, heavily influenced by @axelduch's answer.
差不多三年过去了,但仍在寻找一种一刀切的解决方案。这是受到@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
}, [])
}
Here's a simple example:
这是一个简单的例子:
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 } ]
Here's an example adding parentId
prop via parentRef
.
这里有一个通过parentRef添加parentId支柱的例子。
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' } ]