Merging and reordering two arrays of objects

77 views Asked by At

I'm trying to figure out how to merge two arrays of objects. Here's what I need to do:

  • field property is the unique identifier of each object
  • Output needs to only have the objects listed in the originalArray
  • Order of localStorageArray needs to be maintained, with attention paid to previous requirement (order should be: bar, foo, baz)
  • Output needs to contain the following property values from localStorageArray: hidden and width (field is a give-in, since its the identifier)
  • All other properties of originalArray need to be maintained in output

Here's my wack at it:

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

Full JS Fiddle

I was able to get the properties all right, but I'm a little lost on how to reorder according to localStorageArray. I first thought to do so within the previous set of .forEach() functions, but then I thought not to mess with the order within the forEach loops, since I thought that might mess some things up.

Any suggestions to my solution?

Here are my arrays:

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"
    }];

And here is my desired output:

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
    }];
2

There are 2 answers

1
Xotic750 On BEST ANSWER

Here is an example using ES6 methods.

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

UPDATE: Based on your new comment and data, then this may be a solution.

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>

7
Jyoti Puri On

Check this fiddle: http://jsfiddle.net/j2u2hhk6/

You can actually do it like this:

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