深度减少(可能是?)对象数组

时间:2015-01-30 15:18:48

标签: javascript lodash

我有lodash用于此(或下划线)。我试图获取一个对象数组并将它们变成一个煮沸的对象数组。让我演示给你看。

$scope.myObject = [{
    name: 'Name1', 
    subs: [
        {
            name: 'Sub 1', 
            subs: [
                    {
                        name: 'Sub 1-1', 
                        apps: [
                            {
                            name: 'App 1' 
                            }
                        ]
                    }
            ],
            apps: [
                    {
                        name: 'App'
                    }
            ]
        }

这是原始对象(至少是它的一个节点)。我希望的效果是将其归结为一系列仅仅是“应用程序”的对象。正如你在这里看到的那样,应用程序可以落在任何级别上 - 因此它需要进行某种深度搜索/缩减。这些对象可能会深入10级,并且在任何级别上都有一个app数组。所以我试图把它归结为一个只有应用程序的平面数组,所以例如这个对象会变成:

 [{'name' : 'App 1'},{'name' : 'App'}];

我对这种对象操作还很陌生,所以我可以使用一些指导。谢谢!

4 个答案:

答案 0 :(得分:2)

function pluckRecursive(input, prop, collect) {
    collect = collect || [];

    if (_.isArray(input)) {
        _.forEach(input, function (value, key) {
            pluckRecursive(value, prop, collect);
        })    
    } else if (_.isObject(input)) {
        _.forEach(input, function (value, key) {
            if (key === prop) {
                collect.push(value);
            } else {
                pluckRecursive(value, prop, collect);
            }
        })    
    }

    return collect;
};

当像

一样使用时
pluckRecursive($scope.myObject, 'apps')

返回:

[[{"name":"App 1"}], [{"name":"App"}]]

使用_.flatten()来摆脱嵌套数组。

答案 1 :(得分:1)

您可以像这样使用deep-reduce

const deepReduce = require('deep-reduce')

let apps = deepReduce($scope.myObject, (arr, value, path) => {
  if (path.match(/subs\.\d+\.apps\.\d+$/) {
    arr.push(value)
  }
  return arr
}, [], 'subs')

代码说明:

  • (arr, value, path) => ...是reducer函数。它应该总是返回累积值,这里是应用程序数组。累积值作为第一个参数传递给reducer。
  • value,是对象树中的任何值。它可能是subs数组,subs数组中的对象,或subs.0.name之类的叶值。
  • path是找到当前value的地方。例如subs.0.subs.0.apps。数组的键是数字,这里是0
  • subs\.\d+\.apps\.\d+$匹配以subs.digit.apps.digit结尾的任何路径。我从一开始就省略了^,因为有些应用程序嵌套在subs subs中。您可以在此处试用正则表达式:https://regex101.com/r/n1RfVv/1
  • []arr的初始值。
  • 'subs'告诉deepReduce从该路径开始,这意味着name或根对象中的任何其他属性将被遍历。

速度

根据对象的大小,这可能会很慢,因为deep-reduce遍历整个对象树。如果可能,定义限制遍历的起始路径,如上面的示例中给出的'subs'

如果您的数据源变化不大,您可能需要抓取数据源,进行清理并提供自己的API。

内部工作

如果您对deep-reduce的工作原理感兴趣,可以在此处阅读代码:https://github.com/arve0/deep-reduce/blob/master/index.ts

答案 2 :(得分:0)

您可以使用_.get

本机执行此操作
var object = { 'a': [{ 'b': { 'c': 3 } }] };
 
_.get(object, 'a[0].b.c');
// => 3
 
_.get(object, ['a', '0', 'b', 'c']);
// => 3
 
_.get(object, 'a.b.c', 'default');
// => 'default'

答案 3 :(得分:0)

这里有两个使用 object-scan 的解决方案。第一个在任何地方搜索应用,第二个仅在嵌套的 subs 中搜索。

// const objectScan = require('object-scan');

const myObject = [{ name: 'Name1', subs: [{ name: 'Sub 1', subs: [{ name: 'Sub 1-1', apps: [{ name: 'App 1' }] }], apps: [{ name: 'App' }] }] }];

console.log(objectScan(['**.apps[*]'], { rtn: 'value' })(myObject));
// => [ { name: 'App' }, { name: 'App 1' } ]

console.log(objectScan(['**(^subs$).apps'], { rtn: 'value', useArraySelector: false })(myObject));
// => [ { name: 'App' }, { name: 'App 1' } ]
.as-console-wrapper {max-height: 100% !important; top: 0}
<script src="https://bundle.run/object-scan@13.8.0"></script>

免责声明:我是object-scan

的作者