-2

I have an array of objects that I am currently filtering and mapping, like this:

const countries = [
    "de",
    "fr",
    "nl"
];


const renderDocItem = (doc, country) => {
    return (
        <li className="tabsLi" key={doc._id}>
            <div className="d-flex w-75 justify-content-between">
                <div>
                    {doc.name}
                    <br />
                    <span className="filename">{doc.filename}</span>
                </div>
                <div>
                    {doc.master ? (
                        <img className="flag" src={en} />
                    ) : (
                        <img
                            className="flag"
                            src={objectOfCountries[country]}
                        />
                    )}
                    <span className="action">
                        [
                        <a href="#" onClick={() => view(doc, "view")}>
                            view
                        </a>
                        ,{" "}
                        <a href="#" onClick={() => view(doc, "edit")}>
                            edit
                        </a>
                        ]
                    </span>
                </div>
            </div>
        </li>
    );
};

const renderDocsPerCountry = (docs, country, category) => {
    const filteredDocs = docs.filter((doc) => {
        return doc.countries.includes(country) && doc.category == category;
    });
    const renderedDocs = filteredDocs.map((doc) => {
        return renderDocItem(doc, country);
    });
    console.log(renderedDocs);
    return renderedDocs;
};

<ul>{renderDocsPerCountry(docs, country, "xxx")}</ul>

This creates a list of items, filtered by "xxx" and grouped per country. The problem I have is that some of the items, have the same name property, but different country. I want to be able to group the items with same name.

Current output:

  • Name1, filename1, country1, link
  • Name1, filename2, country2, link
  • Name3, filename3, country3, link

Desired output:

  • Name1, filename1/filename2, country 1 - link / country 2 - link
  • Name3, filename3, country3, link

How would the reduce function look like?

Eric Mitjans
  • 2,149
  • 5
  • 40
  • 69

3 Answers3

1

const data = [
  {
    name: 'Name1',
    filename: 'filename1',
    country: 'country1',
    link: 'link1',
  },
  {
    name: 'Name1',
    filename: 'filename2',
    country: 'country2',
    link: 'link2',
  },
  {
    name: 'Name3',
    filename: 'filename3',
    country: 'country3',
    link: 'link3',
  },
];

const result = data.reduce((prev, current) => {
  const index = prev.findIndex(o => o.name === current.name);
  if (index < 0) {
    prev.push(current);
  } else {
    prev[index].filename = prev[index].filename + ' / ' + current.filename;
    if (prev[index].link) {
      prev[index].country = prev[index].country + ' - ' + prev[index].link + ' / ' + current.country + ' - ' + current.link;
      delete prev[index].link;
    } else {
      prev[index].country = prev[index].country + ' / ' + current.country + ' - ' + current.link;
    }
  }
  return prev;
}, []);

console.log(result);
imhvost
  • 4,750
  • 2
  • 8
  • 10
0

If you want to group items with the same name but different countries, you can use the reduce() function. First, you can use reduce() to create an object that groups the items by name. Then, you can use Object.entries() to iterate over the object and create an array of the grouped items.

const renderDocItem = (doc) => {
  return (
    <div className="d-flex w-75 justify-content-between">
      <div>
        {doc.name}
        <br />
        <span className="filename">{doc.filenames.join("/")}</span>
      </div>
      <div>
        {doc.countries.map((country) => (
          <React.Fragment key={country}>
            {doc.master ? (
              <img className="flag" src={en} />
            ) : (
              <img className="flag" src={objectOfCountries[country]} />
            )}
            <span className="action">
              [
              <a href="#" onClick={() => view(doc, "view")}>
                view
              </a>
              ,{" "}
              <a href="#" onClick={() => view(doc, "edit")}>
                edit
              </a>
              ]
            </span>
            {" - "}
          </React.Fragment>
        ))}
      </div>
    </div>
  );
};

const renderDocsPerCountry = (docs, country, category) => {
  const filteredDocs = docs.filter(
    (doc) =>
      doc.countries.includes(country) && doc.category === category
  );

  const groupedDocs = filteredDocs.reduce((result, doc) => {
    const existingDoc = result.find((d) => d.name === doc.name);

    if (existingDoc) {
      existingDoc.filenames.push(doc.filename);
      existingDoc.countries.push(doc.countries[0]);
    } else {
      result.push({
        name: doc.name,
        filenames: [doc.filename],
        countries: [doc.countries[0]],
        master: doc.master,
      });
    }

    return result;
  }, []);

  return groupedDocs.map((doc) => (
    <li className="tabsLi" key={doc.name}>
      {renderDocItem(doc)}
    </li>
  ));
};

<ul>{renderDocsPerCountry(docs, country, "xxx")}</ul>
2click
  • 106
  • 1
  • 1
  • 5
-1

I could use the map function with JS arrays and maps. Here is some pseudo code:

var map = new Map();
docs.map((doc) => {
    const itemCollection = map.get(doc.filename);
    if (itemCollection == undefined){
      map.set(doc.filename, [doc]); 
    }else{
      itemCollection.push(doc);
      map.set(doc.filename, itemCollection); 
    }
})

The map value will be arrays of items with the same name. Ps: I did not use reduce but achieved the objective of grouping items based on name.

kenn
  • 1,384
  • 12
  • 19
  • 1
    Please do not use `.map()` for simple array iteration. Use `.forEach()` or a normal loop to do that. See: [Is performing a mapping operation without using returned value an antipattern?](https://stackoverflow.com/q/56903693) | [Is performing a mapping operation without using returned value an antipattern?](https://stackoverflow.com/q/56903693) | [Is there a difference between foreach and map?](https://stackoverflow.com/q/354909) | [What is the concept of Array.map?](https://stackoverflow.com/q/17367889) – VLAZ Apr 24 '23 at 09:27