将递归数组对象转换为平面数组对象

时间:2022-03-29 21:31:49

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' } ]