合并和重新排序两个对象数组

Merging and reordering two arrays of objects

我正在尝试弄清楚如何合并两个对象数组。这是我需要做的:

这是我的怪癖:

outputArray.forEach(function(originalItem){
    localStorageArray.forEach(function(localItem){
        if(originalItem.field === localItem.field){
            originalItem.hidden = localItem.hidden;
            originalItem.width = localItem.width;
        }
    });
});  

Full JS Fiddle

我能够获得所有属性,但我对如何根据 localStorageArray 重新排序有点迷茫。我首先想到在前一组 .forEach() 函数中这样做,但后来我认为不要弄乱 forEach 循环中的顺序,因为我认为这可能会弄乱一些事情。

对我的解决方案有什么建议吗?

这是我的数组:

var originalArray = [{
        field: "foo",
        hidden: true,
        sortable: false,
        template: "<div>#=text#</div>",
        width: "20px",
        propA: "a",
        propB: "b"
    }, {
        field: "bar",
        hidden: false,
        sortable: false,
        template: "",
        width: "20%",
        propC: "C"
    }, {
        field: "baz",
        hidden: false,
        sortable: true,
        template: "<span>#=text#</span>",
        int: 3
    }];

var localStorageArray = [{
        field: "bar",
        hidden: false,
        sortable: false,
        width: "100px"
    }, {
        field: "foo",
        hidden: true,
        sortable: false,
        template: "<div>#=text#</div>",
        width: "40px"
    }, {
        field: "boo",
        hidden: true,
        sortable: true,
        template: "<div>Boo: #=text#</div>",
        width: "200px"
    }, {
        field: "baz",
        hidden: true,
        template: "baz:#=text#",
        width: "20px"
    }];

这是我想要的输出:

var desiredArray = [{
        field: "bar",
        hidden: false,
        sortable: false,
        template: "",
        width: "100px",
        propC: "C"
    }, {
        field: "foo",
        hidden: true,
        sortable: false,
        template: "<div>#=text#</div>",
        width: "40px",
        propA: "a",
        propB: "b"
    }, {
        field: "baz",
        hidden: true,
        sortable: true,
        template: "<span>#=text#</span>",
        width: "20px",
        int: 3
    }];

检查此 fiddle:http://jsfiddle.net/j2u2hhk6/

你实际上可以这样做:

var outputArray = [];

localStorageArray.forEach(function(localItem){
    originalArray.forEach(function(originalItem){
        if(originalItem.field === localItem.field){
            var item = JSON.parse(JSON.stringify(originalItem));
            item.hidden = localItem.hidden;
            item.width = localItem.width;
            outputArray.push(item);
        }
    });
});

这里是一个使用 ES6 方法的例子。

/*global document, console, expect */
(function () {
    'use strict';

    var originalArray = [{
            field: 'foo',
            hidden: true,
            sortable: false,
            template: '<div>#=text#</div>',
            width: '20px',
            propA: 'a',
            propB: 'b'
        }, {
            field: 'bar',
            hidden: false,
            sortable: false,
            template: '',
            width: '20%',
            propC: 'C'
        }, {
            field: 'baz',
            hidden: false,
            sortable: true,
            template: '<span>#=text#</span>',
            int: 3
        }],
        localStorageArray = [{
            field: 'bar',
            hidden: false,
            sortable: false,
            width: '100px'
        }, {
            field: 'foo',
            hidden: true,
            sortable: false,
            template: '<div>#=text#</div>',
            width: '40px'
        }, {
            field: 'boo',
            hidden: true,
            sortable: true,
            template: '<div>Boo: #=text#</div>',
            width: '200px'
        }, {
            field: 'baz',
            hidden: true,
            template: 'baz:#=text#',
            width: '20px'
        }],
        desiredArray = [{
            field: 'bar',
            hidden: false,
            sortable: false,
            template: '',
            width: '100px',
            propC: 'C'
        }, {
            field: 'foo',
            hidden: true,
            sortable: false,
            template: '<div>#=text#</div>',
            width: '40px',
            propA: 'a',
            propB: 'b'
        }, {
            field: 'baz',
            hidden: true,
            sortable: true,
            template: '<span>#=text#</span>',
            width: '20px',
            int: 3
        }],
        outputArray = [],
        pre = document.getElementById('out'),
        equalField = function (originalElement) {
            return originalElement.field === this.field;
        };

    localStorageArray.reduce(function (acc, localElement) {
        var original = originalArray.find(equalField, localElement),
            shallowCopy;

        if (original) {
            shallowCopy = Object.assign({}, original);
            shallowCopy.hidden = localElement.hidden;
            shallowCopy.width = localElement.width;
            acc.push(shallowCopy);
        }

        return acc;
    }, outputArray);

    try {
        expect(outputArray).to.eql(desiredArray);
        pre.textContent = 'outputArray is equal to desiredArray\n\n';
    } catch (e) {
        console.error(e);
        pre.textContent = 'outputArray is not equal to desiredArray\n\n';
    }

    pre.textContent += JSON.stringify(outputArray, null, 2);
}());
<script src="https://cdnjs.cloudflare.com/ajax/libs/es6-shim/0.32.0/es6-shim.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/expect.js/0.2.0/expect.min.js"></script>
<pre id="out"></pre>

更新:根据您的新评论和数据,这可能是一个解决方案。

var originalArray = [{
        field: "foo",
        hidden: true,
        sortable: false,
        template: "<div>#=text#</div>",
        width: "20px",
        propA: "a",
        propB: "b"
    }, {
        field: "bee",
        hidden: true,
        sortable: false,
        template: "=#text#",
        int: 4
    }, {
        field: "bar",
        hidden: false,
        sortable: false,
        template: "",
        width: "20%",
        propC: "C"
    }, {
        field: "baz",
        hidden: false,
        sortable: true,
        template: "<span>#=text#</span>",
        int: 3
    }],
    localStorageArray = [{
        field: "bar",
        hidden: false,
        sortable: false,
        width: "100px"
    }, {
        field: "foo",
        hidden: true,
        sortable: false,
        template: "<div>#=text#</div>",
        width: "40px"
    }, {
        field: "boo",
        hidden: true,
        sortable: true,
        template: "<div>Boo: #=text#</div>",
        width: "200px"
    }, {
        field: "baz",
        hidden: true,
        template: "baz:#=text#",
        width: "20px"
    }],
    desiredArray = [{
        field: "bar",
        hidden: false,
        sortable: false,
        template: "",
        width: "100px",
        propC: "C"
    }, {
        field: "bee",
        hidden: true,
        sortable: false,
        template: "=#text#",
        int: 4
    }, {
        field: "foo",
        hidden: true,
        sortable: false,
        template: "<div>#=text#</div>",
        width: "40px",
        propA: "a",
        propB: "b"
    }, {
        field: "baz",
        hidden: true,
        sortable: true,
        template: "<span>#=text#</span>",
        width: "20px",
        int: 3
    }],
    outputArray = [],
    pre = document.getElementById('out'),
    equalField = function (originalElement) {
        return originalElement.field === this.field;
    };

localStorageArray.reduce(function (acc, localElement) {
    var original = originalArray.find(equalField, localElement),
        shallowCopy;

    if (original) {
        shallowCopy = Object.assign({}, original);
        shallowCopy.hidden = localElement.hidden;
        shallowCopy.width = localElement.width;
        acc.push(shallowCopy);
    }

    return acc;
}, outputArray);

originalArray.forEach(function (originalElement, index) {
    if (!this.find(equalField, originalElement)) {
        this.splice(index, 0, Object.assign({}, originalElement));
    }
}, outputArray);

try {
    expect(outputArray).to.eql(desiredArray);
    pre.textContent = 'outputArray is equal to desiredArray\n\n';
} catch (e) {
    console.error(e);
    pre.textContent = 'outputArray is not equal to desiredArray\n\n';
}

pre.textContent += JSON.stringify(outputArray, null, 2);
<script src="https://cdnjs.cloudflare.com/ajax/libs/es6-shim/0.32.0/es6-shim.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/expect.js/0.2.0/expect.min.js"></script>
<pre id="out"></pre>