Home > Enterprise >  why map function not works in a nested objects?
why map function not works in a nested objects?

Time:06-10

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's found field to true when [the] sportTag's name [value] is equal to every person's sport [item]." ... thus the OP does not need to implement a nested, twice map but a map/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; }

  • Related