I have an array contains objects
let sportTag = [
{ id: 1, name: 'FOOTBALL', found: false },
{ id: 2, name: 'TENNIS', found: false },
{ id: 3, name: 'BASKET', found: false },
]
I have also another array contains objects and for every object a field (sports) that is an array
let person = [
{
id: 1,
name: "Mark",
age: 23,
sports: [
"volleyball",
"rugby",
"tennis"
],
},
{
id: 2,
name: "Rupert",
age: 40,
sports: [
"golf"
],
},
{
id: 3,
name: "John",
age: 31,
sports: [
"football",
"golf",
"rugby",
"tennis",
],
},
]
I would like to change sportTag found field to true when sportTag name is equal to every person sport. I tried with a nested map
const result = sportTag.map(st => {
person.map(p => {
p.sports.map(s => {
if (st.name.toLocaleUpperCase() === s.toLocaleUpperCase()) {
return {
...st, found: true
}
}
return s
})
return p
})
return st
})
console.log(sportTag)
//OUTPUT
// { id: 1, name: 'FOOTBALL', found: false },
// { id: 2, name: 'TENNIS', found: false },
// { id: 3, name: 'BASKET', found: false }
console.log(result)
//OUTPUT
// { id: 1, name: 'FOOTBALL', found: false },
// { id: 2, name: 'TENNIS', found: false },
// { id: 3, name: 'BASKET', found: false }
why not changes happends? I'm expecting result is
{ id: 1, name: 'FOOTBALL', found: true},
{ id: 2, name: 'TENNIS', found: true},
{ id: 3, name: 'BASKET', found: false }
CodePudding user response:
The problem with your code is that you are always returning st
for each iteration of the first map
, so you get the original values.
You probably want something like this:
const result = sportTag.map(st => {
const foundSport = person.find(p =>
p.sports.find(s => st.name.toLocaleUpperCase() === s.toLocaleUpperCase())
);
return foundSport
? { ...st, found: true }
: st;
});
console.log(sportTag)
// { id: 1, name: 'FOOTBALL', found: false },
// { id: 2, name: 'TENNIS', found: false },
// { id: 3, name: 'BASKET', found: false }
console.log(result)
// { id: 1, name: 'FOOTBALL', found: true },
// { id: 2, name: 'TENNIS', found: true },
// { id: 3, name: 'BASKET', found: false }
CodePudding user response:
let person = [{
id: 1, name: "Mark", age: 23,
sports: ["volleyball", "rugby", "tennis"],
}, {
id: 2, name: "Rupert", age: 40,
sports: ["golf"],
}, {
id: 3, name: "John", age: 31,
sports: ["football", "golf", "rugby", "tennis"],
}];
let sportTag = [{
id: 1, name: 'FOOTBALL', found: false,
}, {
id: 2, name: 'TENNIS', found: false,
}, {
id: 3, name: 'BASKET', found: false,
}];
sportTag.forEach((elem, index, array) => {
person.forEach((el, i, arr) => {
if (person[i].sports.indexOf(sportTag[index].name.toLocaleLowerCase()) != -1) {
sportTag[index].found = true;
}
});
});
console.log(sportTag);
.as-console-wrapper { min-height: 100%!important; top: 0; }
CodePudding user response:
From the above comment ...
The OP already mentions in the description of the problem the correct way of achieving what the OP wants ... "I would like to change [the]
sportTag
'sfound
field totrue
when [the]sportTag
'sname
[value] is equal toevery
person
'ssport
[item]." ... thus the OP does not need to implement a nested, twicemap
but amap
/every
task.
But (especially for a bigger amount of data) instead following the above suggested approach which within every map
iteration additionally iterates again with every nested every
task one could choose a lookup based approach which works with a Map
instance. The mapping task itself would be very simple. For the latter one could even choose an implementation which makes the mapping agnostic to the current lookup's variable/constant name since one would provide its reference as the map
method's 2nd thisArg
parameter.
One of cause could implement the lookup creation with less iteration cycles. But since it is done once it will never become the performance bottleneck.
function createLookupOfAnyPracticedSport(persons) {
return new Map(
// (5) create a map as lookup for unique sport items.
Array
// (3) create array from set of step (2)
.from(
new Set(
// (2) create a set of unique sport
// items/values as of step (1)
persons
// (1) concatenate array of all `sports`
// practiced by any person.
.reduce((result, { sports }) =>
result.concat(sports), []
)
)
)
// (4) sanitize and map the unique sport items/values
// in order to qualify as entries for step (5) ...
.map(sport => [sport.toLocaleUpperCase(), true])
);
}
function createUpToDateSportTagFromBoundSports(tagItem) {
const allSportsLookup = this;
// create (updated) shallow copy of the original
// sport tag item in order to not directly mutate
// such an item's original reference.
return {
...tagItem,
found: allSportsLookup
.has(tagItem.name.toLocaleUpperCase())
};
}
const personList = [{
id: 1, name: "Mark", age: 23,
sports: ["volleyball", "rugby", "tennis"],
}, {
id: 2, name: "Rupert", age: 40,
sports: ["golf"],
}, {
id: 3, name: "John", age: 31,
sports: ["football", "golf", "rugby", "tennis"],
}];
const sportTagList = [{
id: 1, name: 'FOOTBALL', found: false,
}, {
id: 2, name: 'TENNIS', found: false,
}, {
id: 3, name: 'BASKET', found: false,
}];
const mappedTagList = sportTagList
.map(
createUpToDateSportTagFromBoundSports,
createLookupOfAnyPracticedSport(personList),
);
console.log({
mappedTagList,
sportTagList,
personList,
});
console.log(
'entries of any practiced sport ...',
[...createLookupOfAnyPracticedSport(personList).entries()],
);
.as-console-wrapper { min-height: 100%!important; top: 0; }