如何用更合适的 lodash 函数替换嵌套的 foreach 循环?

How can I replace nested foreach loops with more appropriate lodash functions?

我想完善我的函数式编程知识,更具体地说是 lodash 的数据处理函数。我在下面整理了一个合理的示例,我非常希望看到它以不同的方式完成,最好没有显式的 forEach 循环。

给定以下数据集:

// dateArray JSON
["2015-06-01T04:00:00.000Z", "2015-06-02T04:00:00.000Z", "2015-06-03T04:00:00.000Z"]

// projectList JSON
[{
    "_id": "53d487607464e4954927ba1c",
    "name": "Development"
}, {
    "_id": "540e104f7464e48d2f524560",
    "name": "My Aw&some Proj&ct"
}, {
    "_id": "52168d64839f153950000218",
    "name": "Internal Marketing"
}, {
    "_id": "5464e5787464e42e6df38da8",
    "name": "Communication"
}, {
    "_id": "NA",
    "name": "Not Assigned"
}]

// activeProjectList JSON
[{
    "date": "2015-6-1",
    "projects": [{
        "_id": "53d487607464e4954927ba1c",
        "h": 1
    }, {
        "_id": "NA",
        "h": 2.5
    }]
}, {
    "date": "2015-6-2",
    "projects": [{
        "_id": "540e104f7464e48d2f524560",
        "h": 1
    }, {
        "_id": "NA",
        "h": 2
    }]
}, {
    "date": "2015-6-3",
    "projects": [{
        "_id": "52168d64839f153950000218",
        "h": 1
    }, {
        "_id": "5464e5787464e42e6df38da8",
        "h": 3.25
    }, {
        "_id": "NA",
        "h": 0.5
    }]
}];

您将如何在避免 foreach 循环并支持更合适的 lodash 函数的同时将其压缩成下面的结果?

// series JSON (result)
[{
    "name": "Development",
    "data": [1, 0, 0]
}, {
    "name": "Not Assigned",
    "data": [2.5, 2, 0.5]
}, {
    "name": "My Aw&some Proj&ct",
    "data": [0, 1, 0]
}, {
    "name": "Internal Marketing",
    "data": [0, 0, 1]
}, {
    "name": "Communication",
    "data": [0, 0, 3.25]
}]

这是我目前最好的尝试:

_.map(activeProjectList, function (item) {

    item.date = new Date(item.date).toISOString();

    return item;
});

projectList = _.indexBy(projectList, '_id');

var projectTimes = {};

_.forEach(activeProjectList, function (item) {

    _.forEach(item.projects, function (subItem) {

        if (!projectTimes[subItem._id]) projectTimes[subItem._id] = {};

        projectTimes[subItem._id][item.date] = subItem.h;
    });
});

var series = [];
var seriesData;

_.forEach(projectTimes, function (item, key) {

    seriesData = [];

    _.forEach(dateArray, function (date) {

        if (item[date]) seriesData.push(item[date]);
        else seriesData.push(0);
    });

    series.push({
        name: projectList[key].name,
        data: seriesData
    });
});

这里有一个 fiddle 上面的实现:http://jsfiddle.net/8fe5oo49/

感谢您的宝贵时间。

不确定最终输出的顺序有多重要。对我来说,按最初定义的顺序排列项目列表 return 更有意义,但这可能不是您想要的

var series = _.map(projectList, function(project){
    return {
        'name': project.name,
        'data': _.map(dateArray, function(date){
             var p = _.findWhere(
                 _.find(activeProjectList, function(activeProj){
                    return new Date(activeProj.date).toISOString() == date
                }).projects, 
                {_id: project._id}
             )
             return (p ? p.h : 0) 
        })
    }
});

这将return

[
    {"name":"Development","data":[1,0,0]},
    {"name":"My Aw&some Proj&ct","data":[0,1,0]},
    {"name":"Internal Marketing","data":[0,0,1]},
    {"name":"Communication","data":[0,0,3.25]},
    {"name":"Not Assigned","data":[2.5,2,0.5]}
]