对象数组的深度减少(可能是采摘?)
Deep reduce (pluck maybe?) of array of objects
我有 lodash 可用于此(或下划线)。我正在尝试获取一组对象并将它们变成一个简化的对象数组。我来给你展示。
$scope.myObject = [{
name: 'Name1',
subs: [
{
name: 'Sub 1',
subs: [
{
name: 'Sub 1-1',
apps: [
{
name: 'App 1'
}
]
}
],
apps: [
{
name: 'App'
}
]
}
这是原始对象(至少它的一个节点)。我想要的效果是将它归结为一个对象数组,这些对象只是 'apps'。正如您在此处看到的,应用程序可以属于任何级别 - 因此它需要某种深度 search/reduce。这些对象可能有 10 个级别的深度,并且在任何级别上都有一个应用程序数组。所以我想把它归结为一个只有应用程序的平面数组,所以例如这个对象会变成:
[{'name' : 'App 1'},{'name' : 'App'}];
我对这种对象操作还是很陌生,所以我可以使用一些指导。谢谢!
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')
returns:
[[{"name":"App 1"}], [{"name":"App"}]]
使用 _.flatten()
去除嵌套数组。
您可以这样使用 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函数。它应该总是 return 累积值,这里是应用程序数组。累加值作为第一个参数传递给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
您可以使用 _.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'
这里有两个使用 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
的作者
我有 lodash 可用于此(或下划线)。我正在尝试获取一组对象并将它们变成一个简化的对象数组。我来给你展示。
$scope.myObject = [{
name: 'Name1',
subs: [
{
name: 'Sub 1',
subs: [
{
name: 'Sub 1-1',
apps: [
{
name: 'App 1'
}
]
}
],
apps: [
{
name: 'App'
}
]
}
这是原始对象(至少它的一个节点)。我想要的效果是将它归结为一个对象数组,这些对象只是 'apps'。正如您在此处看到的,应用程序可以属于任何级别 - 因此它需要某种深度 search/reduce。这些对象可能有 10 个级别的深度,并且在任何级别上都有一个应用程序数组。所以我想把它归结为一个只有应用程序的平面数组,所以例如这个对象会变成:
[{'name' : 'App 1'},{'name' : 'App'}];
我对这种对象操作还是很陌生,所以我可以使用一些指导。谢谢!
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')
returns:
[[{"name":"App 1"}], [{"name":"App"}]]
使用 _.flatten()
去除嵌套数组。
您可以这样使用 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函数。它应该总是 return 累积值,这里是应用程序数组。累加值作为第一个参数传递给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
您可以使用 _.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'
这里有两个使用 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
的作者