skip to Main Content

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?

3

Answers


  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.

    Login or Signup to reply.
  2. 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>
    
    Login or Signup to reply.
  3. 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);
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search