Reputation: 94499
I have an array with several category objects, each of which has an items
property containing an array of item objects. I want to map each item in each category to an object[] with objects that have the properties value and label. For some reason, I can't perform the concatenation.
var categories = [{
name: "category1",
items: [{
itemId: 1,
name: "Item1"
}, {
itemId: 2,
name: "Item2"
}]
}, {
name: "category2",
items: [{
itemId: 3,
name: "Item3"
}, {
itemId: 4,
name: "Item4"
}]
}];
var items = [];
for(var i = 0; i < categories.length; i++){
items.concat($.map(categories[i].items,function(elem){
return {value:elem.itemId, label:elem.name};
}));
}
console.log(items); //prints []
Expected Result
[{
label: "Item1",
value: "1"
},
{
label: "Item2",
value: "2"
},{
label: "Item3",
value: "3"
},{
label: "Item4",
value: "4"
}
I feel as if I am missing something very basic. I logged the result of the $.map
function and it appears to be returning an []
. Can anyone figure out the issue?
JSFiddle: http://jsfiddle.net/vymJv/
Upvotes: 16
Views: 45936
Reputation: 1802
Updated with flatMap
(not compatible with IE):
categories.flatMap((categories) => categories.items)
flatMap() method returns a new array formed by applying a given callback function to each element of the array, and then flattening the result by one level.
Upvotes: 17
Reputation: 181
const items = categories
.map(category => category.items)
.reduce((prev, current) => [...prev, ...current])
.map((e, i) => ({ label: e.name, value: e.itemId }));
Upvotes: 4
Reputation: 74420
The concat() method is used to join two or more arrays.
This method does not change the existing arrays, but returns a new array, containing the values of the joined arrays.
for(var i = 0; i < categories.length; i++){
items = items.concat($.map(categories[i].items, function(elem) {
return {value: elem.itemId, label: elem.name};
}));
}
Upvotes: 10
Reputation: 41
This piece of code solves your task using a functional programming approach:
var items = [].concat.apply([], categories.map(cat =>
cat.items.map(elem => ({ value:elem.itemId, label:elem.name })))
)
Explanation: Function.prototype.apply() has the syntax fun.apply(thisArg, [argsArray])
and lets us provide parameters to a function in an array. Array.prototype.concat() combines an arbitrary amount of parameters into one array. If we now write Array.prototype.concat.apply([], [category1Items, ..., categoryNItems])
, it actually equals [].concat(category1Items, ..., categoryNItems)
, which concatenates all parameters together. You can also replace Array.prototype.concat
by [].concat
to keep it shorter. Otherwise we just use standard mapping to get the job done.
You could also split the code apart a bit more for clarity:
function getItem(elem){
return {value:elem.itemId, label:elem.name};
}
function getCategoryItems(cat) {
return cat.items.map(getItem);
}
function flatten(arr) {
return Array.prototype.concat.apply([], arr);
}
var items = flatten(categories.map(getCategoryItems));
Upvotes: 4
Reputation: 192
We could extend the array prototype by creating concatAll which will concatenate all of your arrays by iterating over each subarray, dumping each value into a new array.
Array.prototype.concatAll = function() {
var results = [];
this.forEach(function(subArray) {
subArray.forEach(function(subArrayValue) {
results.push(subArrayValue);
});
});
return results;
};
Then, we can get the desired result with the following:
let items = categories.map(function(category) {
return category.items.map(function(item) {
return {label: item.name, value: item.itemId};
});
}).concatAll();
We get the items by translating each category into an array of items. Because we have two categories, we will end up with two arrays of items. By applying concatAll on the final result, we flatten those two arrays of items and get the desired output.
Upvotes: 3
Reputation: 570
Another method using straight Javascript:
var x = categories.map(function(val) {
return val.items;
}).reduce(function(pre, cur) {
return pre.concat(cur);
}).map(function(e,i) {
return {label:e.name,value:e.itemId};
});
Output: x = [{label: "Item1", value: 1}, {label: "Item2", value: 2}, …]
Upvotes: 29