合并两个不同形状的数据结构

时间:2014-07-09 11:00:06

标签: javascript functional-programming lenses

我有两个不同形状的数据结构来自两个不同的API。数据采用JSON格式,语言为JavaScript。

数组1:

[ { "document" : { "html" : "some_html", "name" : "DOCUMENT_NAME_1" },
    "tooltips" : [ { "html" : "some_html", "name" : "TASK_NAME_1" }, 
                   { "html" : "some_html", "name" : "TASK_NAME_2" } ] },
  { "document" : { "html" : "some_html", "name" : "DOCUMENT_NAME_2" },
    "tooltips" : [ { "html" : "some_html", "name" : "TASK_NAME_3" }, 
                   { "html" : "some_html", "name" : "TASK_NAME_4" } ] }]

数组2:

  [ [ { "name" : "TASK_NAME_1", "status" : "FINISHED" }, 
      { "name" : "TASK_NAME_2", "status" : "OPEN" } ],
    [ { "name" : "TASK_NAME_3", "status" : "OPEN" }, 
      { "name" : "TASK_NAME_4", "status" : "FUTURE" } ] ]

数组1中工具提示字段的元素包含相同的" name" s作为数组2的元素。如何优雅地合并" status"从数组2到数组1中的工具提示?

我认为镜头可能是正确的答案,但我不确定,因为我从未使用它们。

我知道一些方法可以使用嵌套迭代和更新数组1来解决它。我理想地寻找一种不修改现有数据结构的方法。

3 个答案:

答案 0 :(得分:1)

这有点复杂但它应该适合你

array2.forEach(function(tooltips){
    tooltips.forEach(function(tooltip){
        for (var i = 0; i < array1.length; i++) {
            for (var j = 0; j < array1[i].tooltips.length; j++) {
                var arr1Tooltip = array1[i].tooltips[j];
                if(arr1Tooltip.name == tooltip.name)
                    arr1Tooltip.status = tooltip.status;
            };
        };        
    });
});

console.log(JSON.stringify(array1));

答案 1 :(得分:0)

这可能是过度设计而不是非常有效,但您可以使用递归函数与this JSFiddle一样。我太累了,不能巧妙地做到这一点。

var arr1 = [ { "document" : { "html" : "some_html", "name" : "DOCUMENT_NAME_1" },
    "tooltips" : [ { "html" : "some_html", "name" : "TASK_NAME_1" }, 
                   { "html" : "some_html", "name" : "TASK_NAME_2" } ] },
  { "document" : { "html" : "some_html", "name" : "DOCUMENT_NAME_2" },
    "tooltips" : [ { "html" : "some_html", "name" : "TASK_NAME_3" }, 
                   { "html" : "some_html", "name" : "TASK_NAME_4" } ] }];

var arr2 = [ [ { "name" : "TASK_NAME_1", "status" : "FINISHED" }, 
      { "name" : "TASK_NAME_2", "status" : "OPEN" } ],
    [ { "name" : "TASK_NAME_3", "status" : "OPEN" }, 
      { "name" : "TASK_NAME_4", "status" : "FUTURE" } ] ];

var findStatus = function(name, searchArray) {
    var r = '';
    if (typeof searchArray === 'object') {
        if ("name" in searchArray && "status" in searchArray) {
            if (searchArray.name == name) {
                return searchArray.status;
            } else {
                return '';
            }
        } else {
            for (var i in searchArray) {
                r = findStatus(name, searchArray[i]);
                if (r != '') {
                    return r;
                }
            }
        }
    }
    return '';
};

var updateStatus = function(arrToUpdate, arrWithStatus) {
    var copy = $.extend(true, {}, arrToUpdate);
    var r = '';
    if (typeof copy === 'object') {
        if ("name" in copy) {
            r = findStatus(copy.name, arrWithStatus);
            if (r != '') {
                copy.status = r;
            }
        } else {
            for (var i in copy) {
                copy[i] = updateStatus(copy[i], arrWithStatus);
            }
        }
    }
    return copy;
};

var arr3 = updateStatus(arr1, arr2); // Final combined array

我添加了var copy = $.extend(true, {}, arrToUpdate);行,因此它会执行深层复制而不会修改原始数组,因此需要jQuery。

答案 2 :(得分:0)

由于您的数据结构是嵌套的,因此您需要两个zip.map / zipWith s:

zip(array1, array2).map(function([obj, tooltips]) { // ES6 destructuring syntax
    return {
        document: obj.document,
        tooltips: zip(obj.tooltips, tooltips).map(function([tooltip, extender]) {
            return {
                html: tooltip.html,
                name: tooltip.name,
                status: extender.status
            };
        })
    };
})

如果您不想重复这些对象文字结构,您可能可以使用某些复制功能;例如

extend({}, document, {tooltips:…})
extend({}, tooltip, extender);

您也可以使用像https://github.com/DrBoolean/lenseshttps://github.com/fantasyland/fantasy-lenses这样的镜头库,但我不确定这是否值得付出 - 上面的代码只需要下划线/ lodash。

要绕过内部zipWith,你需要一个Traversal镜头(我假设你熟悉this article),但我还没有看到一个JavaScript库,提供这样的。