1
\$\begingroup\$

I am mainly trying to avoid the nested forEach statements and am trying to move towards a lazy evaluation type solution.

jsFiddle

var skus = [{
    "id": 25175837,
    "giftOptions": 1,
    "rmsSkuId": 53750485,
    "available": 1,
    "backOrder": "",
        "channelId": 1,
    "photoGroupId": 0,
    "colorId": 19219,
    "swatchImageUrl": "SwatchSmall/4/_7075044.jpg",
        "size": "1X",
    "color": "Navy",
    "width": null,
    "value": "",
    "price": "$50.00",
    "choiceGroup": "Tall",
        "isHolidayAvailable": true,
    "isSameDayDeliveryAvailable": true
}, {
    "id": 25175838,
    "giftOptions": 1,
    "rmsSkuId": 53750486,
    "available": 1,
    "backOrder": "",
        "channelId": 1,
    "photoGroupId": 7075044,
    "colorId": 159942,
    "swatchImageUrl": "",
        "size": "2X",
    "color": "Navy",
    "width": null,
    "value": "",
    "price": "$50.00",
    "choiceGroup": "Tall",
        "isHolidayAvailable": true,
    "isSameDayDeliveryAvailable": true
}, {
    "id": 25175839,
    "giftOptions": 1,
    "rmsSkuId": 53750487,
    "available": 1,
    "backOrder": "",
        "channelId": 1,
    "photoGroupId": 7075044,
    "colorId": 159942,
    "swatchImageUrl": "",
        "size": "3X",
    "color": "Navy",
    "width": null,
    "value": "",
    "price": "$50.00",
    "choiceGroup": "Tall",
        "isHolidayAvailable": true,
    "isSameDayDeliveryAvailable": true
}, {
    "id": 25175840,
    "giftOptions": 1,
    "rmsSkuId": 53750488,
    "available": 1,
    "backOrder": "",
        "channelId": 1,
    "photoGroupId": 7075044,
    "colorId": 159942,
    "swatchImageUrl": "",
        "size": "4X",
    "color": "Navy",
    "width": null,
    "value": "",
    "price": "$50.00",
    "choiceGroup": "Tall",
        "isHolidayAvailable": true,
    "isSameDayDeliveryAvailable": true
}, {
    "id": 25175841,
    "giftOptions": 1,
    "rmsSkuId": 53750489,
    "available": 1,
    "backOrder": "",
        "channelId": 1,
    "photoGroupId": 7075044,
    "colorId": 159942,
    "swatchImageUrl": "",
        "size": "5X",
    "color": "Navy",
    "width": null,
    "value": "",
    "price": "$50.00",
    "choiceGroup": "Tall",
        "isHolidayAvailable": true,
    "isSameDayDeliveryAvailable": true
}, {
    "id": 25175843,
    "giftOptions": 1,
    "rmsSkuId": 53750508,
    "available": 1,
    "backOrder": "",
        "channelId": 1,
    "photoGroupId": 7075040,
    "colorId": 118311,
    "swatchImageUrl": "SwatchSmall/0/_7075040.jpg",
        "size": "1X",
    "color": "Rl Black",
    "width": null,
    "value": "",
    "price": "$50.00",
    "choiceGroup": "Tall",
        "isHolidayAvailable": true,
    "isSameDayDeliveryAvailable": true
}, {
    "id": 25175844,
    "giftOptions": 1,
    "rmsSkuId": 53750509,
    "available": 1,
    "backOrder": "",
        "channelId": 1,
    "photoGroupId": 7075040,
    "colorId": 118311,
    "swatchImageUrl": "SwatchSmall/0/_7075040.jpg",
        "size": "2X",
    "color": "Rl Black",
    "width": null,
    "value": "",
    "price": "$50.00",
    "choiceGroup": "Tall",
        "isHolidayAvailable": true,
    "isSameDayDeliveryAvailable": true
}, {
    "id": 25175845,
    "giftOptions": 1,
    "rmsSkuId": 53750510,
    "available": 1,
    "backOrder": "",
        "channelId": 1,
    "photoGroupId": 7075040,
    "colorId": 118311,
    "swatchImageUrl": "SwatchSmall/0/_7075040.jpg",
        "size": "3X",
    "color": "Rl Black",
    "width": null,
    "value": "",
    "price": "$50.00",
    "choiceGroup": "Tall",
        "isHolidayAvailable": true,
    "isSameDayDeliveryAvailable": true
}, {
    "id": 25175846,
    "giftOptions": 1,
    "rmsSkuId": 53750511,
    "available": 1,
    "backOrder": "",
    "channelId": 1,
    "photoGroupId": 7075040,
    "colorId": 118311,
    "swatchImageUrl": "SwatchSmall/0/_7075040.jpg",
    "size": "4X",
    "color": "Rl Black",
    "width": null,
    "value": "",
    "price": "$50.00",
    "choiceGroup": "Tall",
    "isHolidayAvailable": true,
    "isSameDayDeliveryAvailable": true
}, {
    "id": 25175847,
    "giftOptions": 1,
    "rmsSkuId": 53750512,
    "available": 1,
    "backOrder": "",
    "channelId": 1,
    "photoGroupId": 7075040,
    "colorId": 118311,
    "swatchImageUrl": "SwatchSmall/0/_7075040.jpg",
    "size": "5X",
    "color": "Rl Black",
    "width": null,
    "value": "",
    "price": "$50.00",
    "choiceGroup": "Tall",
    "isHolidayAvailable": true,
    "isSameDayDeliveryAvailable": true
}];
_(skus)
    .groupBy(function (n) {
        return n.color;
    })
    .forEach(function (n, key) {
        var firstObj = n[0],
            correctColorId = firstObj.colorId;

        // is it possible to chain this forEach to the previous one? or some other
        // cleaner work around
        n.forEach(function (obj, index) {            
            if (obj.colorId !== correctColorId) {
                _.assign(obj, {colorId: correctColorId});
            }
        });
    });

console.log(skus);
\$\endgroup\$
  • \$\begingroup\$ Where do you want to apply lazy evaluation here? \$\endgroup\$ – Pavlo Feb 27 '15 at 21:54
  • \$\begingroup\$ instead of looping through the groups and looping through their contents, I should only need to loop through the specific keys of the groups thats matter \$\endgroup\$ – iamwhitebox Mar 8 '15 at 10:29
3
\$\begingroup\$

Immutable vs. mutable

This is just my opinion, but I often prefer immutable methods over mutable methods. In this case, skus is mutating due to the use of forEach. However, if skus was required elsewhere in its original form, it would require several code changes in order to make it immutable.

For that reason, I often prefer map over forEach as it gives me the choice to mutate the original value or not. map would only require a variable change to make it mutable by assigning the value back to the original variable.

Flat Solution

This problem, one can be solved without forEach and/or nested forEach methods. This solution also requires only 2 passes over the data.

  1. Sort Items by the key field.
  2. Loop through the items and compare them to the previous item.
  3. Resolve any inconsistencies.

The Code

For this demo, instead of mutating skus, the results are stored in a new variable called test. However, to mutate skus, one can just assign the value back to skus.

var test = _.chain(skus)
            .sortBy('color')
            .map(function(item, index, collection) {
                var lastIndex = index - 1;
                if (lastIndex > -1 
                    && item.color === collection[lastIndex].color
                    && item.colorId !== collection[lastIndex].colorId) {
                    item.colorId = collection[lastIndex].colorId;
                }
                return item;
            })
            .value();

Demo

var skus = [{
  "id": 25175837,
  "giftOptions": 1,
  "rmsSkuId": 53750485,
  "available": 1,
  "backOrder": "",
  "channelId": 1,
  "photoGroupId": 0,
  "colorId": 19219,
  "swatchImageUrl": "SwatchSmall/4/_7075044.jpg",
  "size": "1X",
  "color": "Navy",
  "width": null,
  "value": "",
  "price": "$50.00",
  "choiceGroup": "Tall",
  "isHolidayAvailable": true,
  "isSameDayDeliveryAvailable": true
}, {
  "id": 25175838,
  "giftOptions": 1,
  "rmsSkuId": 53750486,
  "available": 1,
  "backOrder": "",
  "channelId": 1,
  "photoGroupId": 7075044,
  "colorId": 159942,
  "swatchImageUrl": "",
  "size": "2X",
  "color": "Navy",
  "width": null,
  "value": "",
  "price": "$50.00",
  "choiceGroup": "Tall",
  "isHolidayAvailable": true,
  "isSameDayDeliveryAvailable": true
}, {
  "id": 25175839,
  "giftOptions": 1,
  "rmsSkuId": 53750487,
  "available": 1,
  "backOrder": "",
  "channelId": 1,
  "photoGroupId": 7075044,
  "colorId": 159942,
  "swatchImageUrl": "",
  "size": "3X",
  "color": "Navy",
  "width": null,
  "value": "",
  "price": "$50.00",
  "choiceGroup": "Tall",
  "isHolidayAvailable": true,
  "isSameDayDeliveryAvailable": true
}, {
  "id": 25175840,
  "giftOptions": 1,
  "rmsSkuId": 53750488,
  "available": 1,
  "backOrder": "",
  "channelId": 1,
  "photoGroupId": 7075044,
  "colorId": 159942,
  "swatchImageUrl": "",
  "size": "4X",
  "color": "Navy",
  "width": null,
  "value": "",
  "price": "$50.00",
  "choiceGroup": "Tall",
  "isHolidayAvailable": true,
  "isSameDayDeliveryAvailable": true
}, {
  "id": 25175841,
  "giftOptions": 1,
  "rmsSkuId": 53750489,
  "available": 1,
  "backOrder": "",
  "channelId": 1,
  "photoGroupId": 7075044,
  "colorId": 159942,
  "swatchImageUrl": "",
  "size": "5X",
  "color": "Navy",
  "width": null,
  "value": "",
  "price": "$50.00",
  "choiceGroup": "Tall",
  "isHolidayAvailable": true,
  "isSameDayDeliveryAvailable": true
}, {
  "id": 25175843,
  "giftOptions": 1,
  "rmsSkuId": 53750508,
  "available": 1,
  "backOrder": "",
  "channelId": 1,
  "photoGroupId": 7075040,
  "colorId": 118311,
  "swatchImageUrl": "SwatchSmall/0/_7075040.jpg",
  "size": "1X",
  "color": "Rl Black",
  "width": null,
  "value": "",
  "price": "$50.00",
  "choiceGroup": "Tall",
  "isHolidayAvailable": true,
  "isSameDayDeliveryAvailable": true
}, {
  "id": 25175844,
  "giftOptions": 1,
  "rmsSkuId": 53750509,
  "available": 1,
  "backOrder": "",
  "channelId": 1,
  "photoGroupId": 7075040,
  "colorId": 118311,
  "swatchImageUrl": "SwatchSmall/0/_7075040.jpg",
  "size": "2X",
  "color": "Rl Black",
  "width": null,
  "value": "",
  "price": "$50.00",
  "choiceGroup": "Tall",
  "isHolidayAvailable": true,
  "isSameDayDeliveryAvailable": true
}, {
  "id": 25175845,
  "giftOptions": 1,
  "rmsSkuId": 53750510,
  "available": 1,
  "backOrder": "",
  "channelId": 1,
  "photoGroupId": 7075040,
  "colorId": 118311,
  "swatchImageUrl": "SwatchSmall/0/_7075040.jpg",
  "size": "3X",
  "color": "Rl Black",
  "width": null,
  "value": "",
  "price": "$50.00",
  "choiceGroup": "Tall",
  "isHolidayAvailable": true,
  "isSameDayDeliveryAvailable": true
}, {
  "id": 25175846,
  "giftOptions": 1,
  "rmsSkuId": 53750511,
  "available": 1,
  "backOrder": "",
  "channelId": 1,
  "photoGroupId": 7075040,
  "colorId": 118311,
  "swatchImageUrl": "SwatchSmall/0/_7075040.jpg",
  "size": "4X",
  "color": "Rl Black",
  "width": null,
  "value": "",
  "price": "$50.00",
  "choiceGroup": "Tall",
  "isHolidayAvailable": true,
  "isSameDayDeliveryAvailable": true
}, {
  "id": 25175847,
  "giftOptions": 1,
  "rmsSkuId": 53750512,
  "available": 1,
  "backOrder": "",
  "channelId": 1,
  "photoGroupId": 7075040,
  "colorId": 118311,
  "swatchImageUrl": "SwatchSmall/0/_7075040.jpg",
  "size": "5X",
  "color": "Rl Black",
  "width": null,
  "value": "",
  "price": "$50.00",
  "choiceGroup": "Tall",
  "isHolidayAvailable": true,
  "isSameDayDeliveryAvailable": true
}];

var test = _.chain(skus)
  .sortBy('color')
  .map(function(item, index, collection) {
    var lastIndex = index - 1;
    if (lastIndex > -1 && item.color === collection[lastIndex].color && item.colorId !== collection[lastIndex].colorId) {
      item.colorId = collection[lastIndex].colorId;
    }
    return item;
  })
  .value();

console.log(test);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/3.5.0/lodash.min.js"></script>
<script src="https://getfirebug.com/firebug-lite-debug.js"></script>

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.