I am mainly trying to avoid the nested forEach
statements and am trying to move towards a lazy evaluation type solution.
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);
-
\$\begingroup\$ Where do you want to apply lazy evaluation here? \$\endgroup\$Pavlo– Pavlo2015年02月27日 21:54:39 +00:00Commented Feb 27, 2015 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\$Jeff Voss– Jeff Voss2015年03月08日 10:29:33 +00:00Commented Mar 8, 2015 at 10:29
1 Answer 1
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.
- Sort Items by the key field.
- Loop through the items and compare them to the previous item.
- 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>