Home > Back-end >  Running a mapping task what is the correct 2nd array method for processing one of the newly created
Running a mapping task what is the correct 2nd array method for processing one of the newly created

Time:06-11

I have an array containing objects:

let sportTag = [
    { id: 1, name: 'FOOTBALL', found: false },
    { id: 2, name: 'TENNIS'  , found: false },
    { id: 3, name: 'BASKET'  , found: false },
]

I have also have another array containing 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 are the changes not reflected in the result? I expect the output to be:

{ 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:

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 [any/some] person's sport [item]." ... thus the OP does not need to implement a nested, twice map but a map/some task.

But (especially for a bigger amount of data) instead of following the above suggested approach which within every map iteration additionally iterates again with every nested some task, one could choose a lookup based approach which works with a Map instance. The mapping task itself will 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; }

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; }

  • Related