william_drew_67
william_drew_67

Reputation: 53

Remove duplicates within the output of a reduce function

I am outputting the matched value of projects when the name of my logo matches the items object within projects with the help of a reduce function. However, whenever I click on multiple logos that both match project.items I am rendering duplicates.

Here is my code:

logos.reduce((acc, logo) => {
    if (logo.active) {
        Object.values(projects).forEach((proj) => {
           if (Object.values(proj.items).includes(logo.name)) {
              console.log(acc)
              acc.push((<Project title={proj.title} routeName={proj.routeName} items={proj.items} description={proj.description}/>));
           }
        });
    }
      return acc
}, [])

My first idea was to create another array, run a for loop and iterate through the values like: filteredValues[i].props.title and push the contents of that loop to an array. I ran run a reduce on that array like this but I was not able to eliminate the duplicate:

const filteredArr = arr.reduce((acc, current) => {
  const x = acc.find(item => item.title === current.title);
  if (!x) {
    return acc.concat([current]);
  } else {
    return acc;
  }
}, []);

Anyway, here's the output of acc which I am using to render my Project component

enter image description here

Upvotes: 0

Views: 1367

Answers (4)

william_drew_67
william_drew_67

Reputation: 53

I had to run a reduce function outside of the original forEach loop and check those values with a some function.

    logos.reduce((acc, logo) => {
      if (logo.active) {
          Object.values(projects).forEach((proj) => {
             if (Object.values(proj.items).includes(logo.name)) {
               console.log(acc)

               acc.push((<Project title={proj.title} routeName={proj.routeName} items={proj.items} description={proj.description}/>));
             }
          });
          acc = acc.reduce(function (p, c) {
            if (!p.some(function (el) { return el.props.title === c.props.title; })) p.push(c);
            return p;
          }, []);
      }
        return acc
  }, [])

Upvotes: 0

Shoma
Shoma

Reputation: 499

May be below code is what you need.

const filteredArr = this.getUnique(arr, 'title'); 

getUnique(arr, comp) {
   const unique =  arr.map(e => e[comp]).map((e, i, final) => final.indexOf(e) === i && i).filter((e) => arr[e]).map(e => arr[e]);

   return unique;
}

Steps involve is to:

  1. Store the comparison values in array "arr.map(e => e[comp])"
  2. Store the indexes of the unique objects ".....).map((e, i, final) => final.indexOf(e) === i && i)"
  3. Eliminate the false indexes & return unique objects ".....).filter((e) => arr[e]).map(e => arr[e])"

Upvotes: 2

terrymorse
terrymorse

Reputation: 7096

You can use the Map object to filter out duplicates.

let arrFiltered = [];

// form map of unique arr items
const arrMap = new Map();
arr.forEach(item => arrMap.set(item.title, item));

// form array of all items in map
arrMap.forEach(item => arrFiltered.push(item));

Upvotes: 0

Manan Joshi
Manan Joshi

Reputation: 679

You can write your original loop like this

logos
  .reduce((acc, logo) => {
    if (logo.active) {
      Object.values(projects).forEach((proj) => {
        if (
          Object.values(proj.items).includes(logo.name) &&
          !acc.find((item) => item.value === logo.name)
        ) {
          console.log(acc);
          acc.push({
            value: logo.name,
            component: (
              <Project
                title={proj.title}
                routeName={proj.routeName}
                items={proj.items}
                description={proj.description}
              />
            ),
          });
        }
      });
    }
    return acc;
  }, [])
  .map((values) => values.component);

Upvotes: 0

Related Questions