I have an array
const countries = [{
name: "Angola",
region: "Africa"
}, {
name: "Spain",
region: "Europe"
}, {
name: "Italy",
region: "Europe"
}]
I need the result to be:
const result = {
Europe: [{
name: "Spain"
}, {
name: "italy"
}],
Africa: [{
name: "Angola"
}]
}
I've tried 2 approaches:
- Approach 1:
const result = countries.reduce((acc, {
name,
region
}) => {
acc[region] = [...acc[region], {
name
}]
return acc
}, {})
- Approach 2:
const result = countries.reduce((acc, {
name,
region
}) => {
return {
...acc,
[region]: [...acc[region], {
name
}]
}
}, {})
None of them work because I couldn't find a way to spread the existing items in the array, which at a first iteration is obviously null.
Thanks
CodePudding user response:
I wouldn't use reduce
for this at all. If you're not doing functional programming with predefined, reusable reducer functions, reduce
is just an overcomplicated loop — hard to read, easy to get wrong.
Instead, I'd just use a loop:
const result = {};
for (const { name, region } of countries) {
let entry = result[region];
if (!entry) {
entry = result[region] = [];
}
entry.push({ name });
}
const countries = [
{
name: "Angola",
region: "Africa",
},
{
name: "Spain",
region: "Europe",
},
{
name: "Italy",
region: "Europe",
},
];
const result = {};
for (const { name, region } of countries) {
let entry = result[region];
if (!entry) {
entry = result[region] = [];
}
entry.push({ name });
}
console.log(result);
.as-console-wrapper {
max-height: 100% !important;
}
But since you did specifically ask for reduce
, you can do it that way (any array operation can be shoehorned into a reduce
):
const result = countries.reduce((result, { name, region }) => {
let entry = result[region];
if (!entry) {
entry = result[region] = [];
}
entry.push({ name });
return result;
}, {});
const countries = [
{
name: "Angola",
region: "Africa",
},
{
name: "Spain",
region: "Europe",
},
{
name: "Italy",
region: "Europe",
},
];
const result = countries.reduce((result, { name, region }) => {
let entry = result[region];
if (!entry) {
entry = result[region] = [];
}
entry.push({ name });
return result;
}, {});
console.log(result);
.as-console-wrapper {
max-height: 100% !important;
}
Or more FP-style by creating new objects and arrays on every loop (but there's no point in this case):
const result = countries.reduce((result, { name, region }) => {
const entry = result[region] ?? [];
return {
...result,
[region]: [...entry, { name }],
};
}, {});
const countries = [
{
name: "Angola",
region: "Africa",
},
{
name: "Spain",
region: "Europe",
},
{
name: "Italy",
region: "Europe",
},
];
const result = countries.reduce((result, { name, region }) => {
const entry = result[region] ?? [];
return {
...result,
[region]: [...entry, { name }],
};
}, {});
console.log(result);
.as-console-wrapper {
max-height: 100% !important;
}
CodePudding user response:
Suddenly I found the solution to my problem
const result = countries.reduce((acc, {
name,
region
}) => {
return {
...(acc || {}),
[region]: [...(acc[region] || []), {
name
}]
}
}, {})
CodePudding user response:
You can solve the problem by defining acc[region]
const result = countries.reduce((acc, {
name,
region
}) => {
if (!acc[region]) acc[region] = [];
acc[region] = [...acc[region], {
name
}]
return acc
}, {})