Javascript 如何从地图 return 数组
Javascript how to return array from map
我有以下Json
var myjson = [{
"files": [
{
"domain": "d",
"units": [
{
"key": "key1",
"type": "2"
},
{
"key": "key2",
"type": "2"
},
{
"key": "key3",
"type": "2"
}]
},
{
"domain": "d1",
"units": [
{
"key": "key11",
"type": "2"
},
{
"key": "key12",
"type": "2"
},
{
"key": "key13",
"type": "2"
}]
}]
},
{
"files": [
{
"domain": "d",
"units": [
{
......
我想从这个 Json 数组创建一个新数组。数组的长度将是此 Json 对象中 "units" 的数量。
所以我需要提取 "units" 并从父对象添加一些数据。
units: [{
domain: "",
type: "",
key: ""
}, {
domain: "",
type: "",
key: ""
},
{
domain: "",
type: "",
key: ""
}
....
];
我想我可能会做这样的事情:
var res = [];
myjson.forEach(function(row) {
row.files.forEach(function(tfile) {
tfile.units.forEach(function(unit) {
var testEntity = {
domain: tfile.domain,
type : unit.type,
key: unit.key
};
res.push(testEntity);
});
});
});
但它很难读,而且看起来不太好。我正在考虑做类似的事情:
var RESULT = myjson.map(function(row) {
return row.files.map(function(tfile) {
return tfile.units.map(function(unit) {
return {
domain: tfile.domain,
type : unit.type,
key: unit.key
};
});
});
});
但这不起作用,而且看起来也不好。有什么办法可以做到这一点,也许以更具声明性的方式。希望 Ramda.js 能有所帮助。
一般来说,有没有什么好的方法可以以可读的方式从任何嵌套 json 中获取数据?
实施类似:
nestedjson.findAllOnLastlevel(function(item){
return {
key : item.key,
type: type.key,
domain : item.parent.domain}
});
或者以某种方式将此 json 展平,以便所有父对象的所有属性都移动到叶子子对象中。 myjson.flatten("files.units")
jsbin http://jsbin.com/hiqatutino/edit?css,js,console
非常感谢
像这样的东西应该有用。 .reduce
适合这种情况。
const allUnits = myjson.reduce((acc, anonObj) => {
const units = anonObj.files.map(fileObj => {
return fileObj.units.map(unit => {
return {...unit, domain: fileObj.domain})
})
return [...acc, ...units]
}, [])
请注意,这依赖于数组传播和对象传播,这是并非每个平台都支持的 ES6 功能。
如果您不会使用 ES6,这里有一个 ES5 实现。不那么漂亮,但做同样的事情:
var allUnits = myjson.reduce(function (acc, anonObj) {
const units = anonObj.files.map(function(fileObj) {
// for each fileObject, return an array of processed unit objects
// with domain property added from fileObj
return fileObj.units.map(function(unit) {
return {
key: unit.key,
type: unit.type,
domain: fileObj.domain
}
})
})
// for each file array, add unit objects from that array to accumulator array
return acc.concat(units)
}, [])
试试这个
var myjson = [{
"files": [{
"domain": "d",
"units": [{
"key": "key1",
"type": "2"
}, {
"key": "key2",
"type": "2"
}, {
"key": "key3",
"type": "2"
}]
},
{
"domain": "d1",
"units": [{
"key": "key11",
"type": "2"
}, {
"key": "key12",
"type": "2"
}, {
"key": "key13",
"type": "2"
}]
}
]
}];
//first filter out properties exluding units
var result = [];
myjson.forEach(function(obj){
obj.files.forEach(function(obj2){
result = result.concat(obj2.units.map(function(unit){
unit.domain = obj2.domain;
return unit;
}));
});
});
console.log(result);
您可以在这里使用的函数是 Ramda 的 R.chain
函数而不是 R.map
。您可以将 R.chain
视为一种映射列表的方法,该函数具有 returns 另一个列表,然后将结果列表拼合在一起。
// get a list of all files
const listOfFiles =
R.chain(R.prop('files'), myjson)
// a function that we can use to add the domain to each unit
const unitsWithDomain =
(domain, units) => R.map(R.assoc('domain', domain), units)
// take the list of files and add the domain to each of its units
const result =
R.chain(file => unitsWithDomain(file.domain, file.units), listOfFiles)
如果您想更进一步,那么您还可以使用 R.pipeK
这有助于组合函数,这些函数在每个给定函数之间的行为类似于 R.chain
。
// this creates a function that accepts the `myjson` list
// then passes the list of files to the second function
// returning the list of units for each file with the domain attached
const process = pipeK(prop('files'),
f => map(assoc('domain', f.domain), f.units))
// giving the `myjson` object produces the same result as above
process(myjson)
纯 JS 足以在简单的一行中生成结果。我不会为了这份工作而接触任何图书馆。我在这里有两种方法。第一个是 reduce.reduce.map 链,第二个是 reduce.map.map 链。这是代码;
var myjson = [{"files":[{"domain":"d","units":[{"key":"key1","type":"2"},{"key":"key2","type":"2"},{"key":"key3","type":"2"}]},{"domain":"d1","units":[{"key":"key11","type":"2"},{"key":"key12","type":"2"},{"key":"key13","type":"2"}]}]},{"files":[{"domain":"e","units":[{"key":"key1","type":"2"},{"key":"key2","type":"2"},{"key":"key3","type":"2"}]},{"domain":"e1","units":[{"key":"key11","type":"2"},{"key":"key12","type":"2"},{"key":"key13","type":"2"}]}]}],
units = myjson.reduce((p,c) => c.files.reduce((f,s) => f.concat(s.units.map(e => (e.domain = s.domain,e))) ,p) ,[]);
units2 = myjson.reduce((p,c) => p.concat(...c.files.map(f => f.units.map(e => (e.domain = f.domain,e)))) ,[]);
console.log(units);
console.log(units2);
为了 ES5 兼容性,我建议使用 reduce.reduce.map 链,因为不需要扩展运算符。并将箭头函数替换为传统的箭头函数,如下所示;
var myjson = [{"files":[{"domain":"d","units":[{"key":"key1","type":"2"},{"key":"key2","type":"2"},{"key":"key3","type":"2"}]},{"domain":"d1","units":[{"key":"key11","type":"2"},{"key":"key12","type":"2"},{"key":"key13","type":"2"}]}]},{"files":[{"domain":"e","units":[{"key":"key1","type":"2"},{"key":"key2","type":"2"},{"key":"key3","type":"2"}]},{"domain":"e1","units":[{"key":"key11","type":"2"},{"key":"key12","type":"2"},{"key":"key13","type":"2"}]}]}],
units = myjson.reduce(function(p,c) {
return c.files.reduce(function(f,s) {
return f.concat(s.units.map(function(e){
e.domain = s.domain;
return e;
}));
},p);
},[]);
console.log(units);
我有以下Json
var myjson = [{
"files": [
{
"domain": "d",
"units": [
{
"key": "key1",
"type": "2"
},
{
"key": "key2",
"type": "2"
},
{
"key": "key3",
"type": "2"
}]
},
{
"domain": "d1",
"units": [
{
"key": "key11",
"type": "2"
},
{
"key": "key12",
"type": "2"
},
{
"key": "key13",
"type": "2"
}]
}]
},
{
"files": [
{
"domain": "d",
"units": [
{
......
我想从这个 Json 数组创建一个新数组。数组的长度将是此 Json 对象中 "units" 的数量。
所以我需要提取 "units" 并从父对象添加一些数据。
units: [{
domain: "",
type: "",
key: ""
}, {
domain: "",
type: "",
key: ""
},
{
domain: "",
type: "",
key: ""
}
....
];
我想我可能会做这样的事情:
var res = [];
myjson.forEach(function(row) {
row.files.forEach(function(tfile) {
tfile.units.forEach(function(unit) {
var testEntity = {
domain: tfile.domain,
type : unit.type,
key: unit.key
};
res.push(testEntity);
});
});
});
但它很难读,而且看起来不太好。我正在考虑做类似的事情:
var RESULT = myjson.map(function(row) {
return row.files.map(function(tfile) {
return tfile.units.map(function(unit) {
return {
domain: tfile.domain,
type : unit.type,
key: unit.key
};
});
});
});
但这不起作用,而且看起来也不好。有什么办法可以做到这一点,也许以更具声明性的方式。希望 Ramda.js 能有所帮助。
一般来说,有没有什么好的方法可以以可读的方式从任何嵌套 json 中获取数据?
实施类似:
nestedjson.findAllOnLastlevel(function(item){
return {
key : item.key,
type: type.key,
domain : item.parent.domain}
});
或者以某种方式将此 json 展平,以便所有父对象的所有属性都移动到叶子子对象中。 myjson.flatten("files.units")
jsbin http://jsbin.com/hiqatutino/edit?css,js,console
非常感谢
像这样的东西应该有用。 .reduce
适合这种情况。
const allUnits = myjson.reduce((acc, anonObj) => {
const units = anonObj.files.map(fileObj => {
return fileObj.units.map(unit => {
return {...unit, domain: fileObj.domain})
})
return [...acc, ...units]
}, [])
请注意,这依赖于数组传播和对象传播,这是并非每个平台都支持的 ES6 功能。
如果您不会使用 ES6,这里有一个 ES5 实现。不那么漂亮,但做同样的事情:
var allUnits = myjson.reduce(function (acc, anonObj) {
const units = anonObj.files.map(function(fileObj) {
// for each fileObject, return an array of processed unit objects
// with domain property added from fileObj
return fileObj.units.map(function(unit) {
return {
key: unit.key,
type: unit.type,
domain: fileObj.domain
}
})
})
// for each file array, add unit objects from that array to accumulator array
return acc.concat(units)
}, [])
试试这个
var myjson = [{
"files": [{
"domain": "d",
"units": [{
"key": "key1",
"type": "2"
}, {
"key": "key2",
"type": "2"
}, {
"key": "key3",
"type": "2"
}]
},
{
"domain": "d1",
"units": [{
"key": "key11",
"type": "2"
}, {
"key": "key12",
"type": "2"
}, {
"key": "key13",
"type": "2"
}]
}
]
}];
//first filter out properties exluding units
var result = [];
myjson.forEach(function(obj){
obj.files.forEach(function(obj2){
result = result.concat(obj2.units.map(function(unit){
unit.domain = obj2.domain;
return unit;
}));
});
});
console.log(result);
您可以在这里使用的函数是 Ramda 的 R.chain
函数而不是 R.map
。您可以将 R.chain
视为一种映射列表的方法,该函数具有 returns 另一个列表,然后将结果列表拼合在一起。
// get a list of all files
const listOfFiles =
R.chain(R.prop('files'), myjson)
// a function that we can use to add the domain to each unit
const unitsWithDomain =
(domain, units) => R.map(R.assoc('domain', domain), units)
// take the list of files and add the domain to each of its units
const result =
R.chain(file => unitsWithDomain(file.domain, file.units), listOfFiles)
如果您想更进一步,那么您还可以使用 R.pipeK
这有助于组合函数,这些函数在每个给定函数之间的行为类似于 R.chain
。
// this creates a function that accepts the `myjson` list
// then passes the list of files to the second function
// returning the list of units for each file with the domain attached
const process = pipeK(prop('files'),
f => map(assoc('domain', f.domain), f.units))
// giving the `myjson` object produces the same result as above
process(myjson)
纯 JS 足以在简单的一行中生成结果。我不会为了这份工作而接触任何图书馆。我在这里有两种方法。第一个是 reduce.reduce.map 链,第二个是 reduce.map.map 链。这是代码;
var myjson = [{"files":[{"domain":"d","units":[{"key":"key1","type":"2"},{"key":"key2","type":"2"},{"key":"key3","type":"2"}]},{"domain":"d1","units":[{"key":"key11","type":"2"},{"key":"key12","type":"2"},{"key":"key13","type":"2"}]}]},{"files":[{"domain":"e","units":[{"key":"key1","type":"2"},{"key":"key2","type":"2"},{"key":"key3","type":"2"}]},{"domain":"e1","units":[{"key":"key11","type":"2"},{"key":"key12","type":"2"},{"key":"key13","type":"2"}]}]}],
units = myjson.reduce((p,c) => c.files.reduce((f,s) => f.concat(s.units.map(e => (e.domain = s.domain,e))) ,p) ,[]);
units2 = myjson.reduce((p,c) => p.concat(...c.files.map(f => f.units.map(e => (e.domain = f.domain,e)))) ,[]);
console.log(units);
console.log(units2);
为了 ES5 兼容性,我建议使用 reduce.reduce.map 链,因为不需要扩展运算符。并将箭头函数替换为传统的箭头函数,如下所示;
var myjson = [{"files":[{"domain":"d","units":[{"key":"key1","type":"2"},{"key":"key2","type":"2"},{"key":"key3","type":"2"}]},{"domain":"d1","units":[{"key":"key11","type":"2"},{"key":"key12","type":"2"},{"key":"key13","type":"2"}]}]},{"files":[{"domain":"e","units":[{"key":"key1","type":"2"},{"key":"key2","type":"2"},{"key":"key3","type":"2"}]},{"domain":"e1","units":[{"key":"key11","type":"2"},{"key":"key12","type":"2"},{"key":"key13","type":"2"}]}]}],
units = myjson.reduce(function(p,c) {
return c.files.reduce(function(f,s) {
return f.concat(s.units.map(function(e){
e.domain = s.domain;
return e;
}));
},p);
},[]);
console.log(units);