Javascript如何从地图返回数组

时间:2016-06-20 10:11:51

标签: javascript arrays ramda.js

我有以下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: [{
        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,以便将所有父对象的所有属性移动到leafs子对象。 myjson.flatten( “files.units”)

jsbin http://jsbin.com/hiqatutino/edit?css,js,console

非常感谢

4 个答案:

答案 0 :(得分:5)

您可以在此处使用的功能是Ramda的R.chain功能,而不是R.map。您可以将R.chain视为使用返回另一个列表的函数映射列表的方法,然后将生成的列表列表展平在一起。

// 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)

答案 1 :(得分:2)

纯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);

答案 2 :(得分:1)

这样的事情应该有效。对于这种情况,.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)
}, [])

答案 3 :(得分:0)

试试这个

 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);