I want to add items from one array to another array. I have a solution but to be honest I wonder if it is scalable at all. I make two database queries. Currently there are not many items, but there might be a lot of items, and then I don't know whether the solution is still suitable.
**Is there a resource-saving solution?
const brands = [
{"id":1,"name":"brand_1","img_name":""},
{"id":2,"name":"brand_2","img_name":""},
{"id":4,"name":"brand_3","img_name":""},
{"id":3,"name":"brand_4","img_name":""}];
const models = [{"id":1,"name":"model_2","img_name":"","brand_id":2},{"id":2,"name":"model_1","img_name":"","brand_id":2},{"id":3,"name":"model_2","img_name":"","brand_id":2},{"id":4,"name":"model_2","img_name":"","brand_id":2},{"id":5,"name":"model_2","img_name":"","brand_id":2},{"id":6,"name":"model_2","img_name":"","brand_id":2},{"id":7,"name":"model_2","img_name":"","brand_id":2},{"id":8,"name":"model_2","img_name":"","brand_id":2}];
models.forEach(e => {
brands.forEach(a => {
if (! a.models) {
a.models = [];
}
if (a.id === e.brand_id) {
a.models.push(e)
}
})
})
console.log(brands);
CodePudding user response:
Since the target structure is derived from the brands
array and its items, one needs to map
this array once.
In order to not to introduce another nested iteration one would want to create and assign a new brand
item's model
array from a lookup-table which holds the latter as references of a grouping key where the key equals both a brand
item's id
-value and a model
item's brand_id
-value.
The lookup will be created by a reduce
task which iterates the models
array once.
Thus the above described and beneath implemented approach prevents nested array iterations.
const brands = [
{ id: 1, name: "brand_1", img_name: "" },
{ id: 2, name: "brand_2", img_name: "" },
{ id: 3, name: "brand_3", img_name: "" },
{ id: 4, name: "brand_4", img_name: "" },
];
const models = [
{ id: 1, name: "model_1", img_name: "", brand_id: 2 },
{ id: 2, name: "model_2", img_name: "", brand_id: 2 },
{ id: 3, name: "model_3", img_name: "", brand_id: 2 },
{ id: 4, name: "model_4", img_name: "", brand_id: 2 },
{ id: 5, name: "model_5", img_name: "", brand_id: 2 },
{ id: 1, name: "model_1", img_name: "", brand_id: 1 },
{ id: 2, name: "model_2", img_name: "", brand_id: 1 },
{ id: 1, name: "model_1", img_name: "", brand_id: 4 },
];
// create an object based model lookup
// where each model gets collected in
// an array which is grouped by the
// model's `brand_id` property value.
const modelsByBrandId = models
.reduce((lookup, model) => {
// access or create the grouped model array.
(lookup[model.brand_id] ??= []).push(model);
return lookup;
}, {});
console.log({ modelsByBrandId });
// map the `brands` array by creating each
// a new (and decoupled from the original
// reference) brand item where the brand-
// `id` related `models` array gets picked
// from the mapper function's bound lookup.
const result = brands
.map(function assignModelsFromBoundLookup(brand) {
const lookup = this;
// create a new brand item which is
// decoupled from its passed reference.
return {
...brand,
models: (brand.models ?? [])
.concat(lookup[brand.id] ?? []),
};
}, modelsByBrandId);
console.log({ result });
.as-console-wrapper { min-height: 100%!important; top: 0; }
I personally recommend a final code iteration where one implements both the mapper and the reducer function as function statements.
It contributes to a better readability, code-reuse and performance too.
// create and programmatically build an object based model lookup
// where each model gets collected in an array which is grouped
// by the model's `brand_id` property value.
function collectItemIntoBrandIdGroupedModels(lookup, model) {
// access or create the grouped model array.
(lookup[model.brand_id] ??= []).push(model);
return lookup;
}
// create a new (and decoupled from the original reference)
// brand item where the brand-`id` related `models` array
// gets picked from the mapper function's bound lookup.
function assignModelsFromBoundLookup(brand) {
const lookup = this;
// create new brand item.
return {
...brand,
models: (brand.models ?? [])
.concat(lookup[brand.id] ?? []),
};
}
const brands = [
{ id: 1, name: "brand_1", img_name: "" },
{ id: 2, name: "brand_2", img_name: "" },
{ id: 3, name: "brand_3", img_name: "" },
{ id: 4, name: "brand_4", img_name: "" },
];
const models = [
{ id: 1, name: "model_1", img_name: "", brand_id: 2 },
{ id: 2, name: "model_2", img_name: "", brand_id: 2 },
{ id: 3, name: "model_3", img_name: "", brand_id: 2 },
{ id: 4, name: "model_4", img_name: "", brand_id: 2 },
{ id: 5, name: "model_5", img_name: "", brand_id: 2 },
{ id: 1, name: "model_1", img_name: "", brand_id: 1 },
{ id: 2, name: "model_2", img_name: "", brand_id: 1 },
{ id: 1, name: "model_1", img_name: "", brand_id: 4 },
];
const result = brands
.map(
assignModelsFromBoundLookup,
models
.reduce(collectItemIntoBrandIdGroupedModels, {}),
);
console.log({ result });
.as-console-wrapper { min-height: 100%!important; top: 0; }