2

I am creating a menu application using React. My app accepts an array of objects which then need to be mapped into a menu. The structure of the menu is like this:

Title
  Header
    Item
    Item
  Header
    Item
    Item

The data objects I receive are structured like: {title: "Drinks", header: "Beer", item: "Blue Moon"}. I filter the array so I only get objects with the same title. My issue is that I do not know how many different headers are going to come in. I need my mapping function to display each header and all associated items. Currently the title is handled outside of the mapping function because there will only be one title per menu.

        <div className={style.menuItemTitle}>{title}</div>
        {currentMenu.map((item, index) => (
          <div className={style.menuHeader}>{item.header}</div>
          <div className={style.menuItem}>{item.item}</div>
        ))}

The above code lists the header above every single item. I only want each header to display once with all of the associated items below.

6
  • currentMenu.filter(item=>item.header==='beer').map(element=>element.item) gives list of items Commented Feb 16, 2021 at 20:07
  • I don't know what each header is going to be though. Commented Feb 16, 2021 at 20:09
  • I would suggest using a different data structure, like { title: "Drinks", items: [ { header: "Beer", items: [ { name: "Blue Moon" }, { name: "Heineken" } ] }, { header: "Liquor", items: [ { name: "Jameson Irish Whiskey" }, { name: "Stolichnaya Vodka" } ] } Then it would be easier to map them. Commented Feb 16, 2021 at 20:10
  • @tdammon, try this: const uniqueHeaders=(menu)=>{ let result=[]; for (let item of menu){ if (result.indexOf(item.header)===-1){ result.push(item.header)}; }; return result} it returns array of unique headers Commented Feb 16, 2021 at 20:24
  • That will get me an array of the unique headers but I still need to map everything into the menu. Commented Feb 16, 2021 at 20:25

3 Answers 3

1
let array = [1,2,3,4,5,2,4,3];
let unq = array.filter((itm,pos,self)=>{ return self.indexOf(itm) == pos});

Unq = [1, 2, 3, 4, 5]

For nested array

let menu = {"title":"Drinks","items":[{"header":"Beer","items":[{"name":"Blue Moon"},{"name":"Heineken"}]},{"header":"Beer","items":[{"name":"Blue Moon"},{"name":"Heineken"}]},{"header":"Liquor","items":[{"name":"Jameson Irish Whiskey"},{"name":"Stolichnaya Vodka"}]}]}

From https://stackoverflow.com/a/64489112/14499047

const uniq_arr = (x,f)=>Object.values(x.reduce((a,b)=>((a[f(b)]=b),a),{}));
let header = uniq_arr(menu.items,(v)=> v.header);
for(item in header) {
    let header_name  = header[item].header //Header Name
    let lists = header[item].items; // Header List
    for (list in lists) {
        lists[list].name // Names in heaeder list
    }
}

Result

  • Drinks
    • Beer
      • Blue Moon
      • Heineken
    • Liquor
      • Jameson Irish Whiskey
      • Stolichnaya Vodka

let body = $('body');
    window.menu = {"title":"Drinks","items":[{"header":"Beer","items":[{"name":"Blue Moon"},{"name":"Heineken"}]},{"header":"Beer","items":[{"name":"Blue Moon"},{"name":"Heineken"}]},{"header":"Liquor","items":[{"name":"Jameson Irish Whiskey"},{"name":"Stolichnaya Vodka"}]}]};
    const uniq_arr = (x,f)=>Object.values(x.reduce((a,b)=>((a[f(b)]=b),a),{}));
    let header = uniq_arr(menu.items,(v)=> v.header);
    body.append($('<ul/>').append($('<li/>').attr('id','menu').text(menu.title)));
    for(item in header) {
        $('#menu').append($('<ul/>').append($('<li/>').attr('id',header[item].header+'_header').text(header[item].header)));
        let lists = header[item].items;
        for (list in lists) $('#'+header[item].header+'_header').append($('<ul/>').append($('<li/>').text(lists[list].name)));
        
    }
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

Sign up to request clarification or add additional context in comments.

2 Comments

This is just perfect!
@arturasmckwcz take look at, updated code for the nested arrays.
0
const uniqueHeaders=(menu)=>{
  let result=[];
  for (let item of menu){
    if (result.indexOf(item.header)===-1){
      result.push(item.header)
    };
  };
  return result
}

uniqueHeaders(currentMenu).map(uniqueHeader=>
  currentMenu.filter(item=>
    item.header===uniqueHeader).map(element=>
      element.item))

3 Comments

I think this is very close but I am getting the following error still "Objects are not valid as a React child (found: object with keys {title, header, item}). If you meant to render a collection of children, use an array instead."
This code should return an array containing arrays with items for each unique header. Say it was 3 beers and 2 wines, the result should be [[beer1,beer2,beer3],[wine1,wine2]] It isn't easy to help you with react error without seeing the code.
You're most welcome! BTW I'd suggest you use @ANOL GHOSH answer and replace uniqueHeaders(currentMenu) with his perfect line of code.
0

Try this snippet, the idea here is to group by the title

let list=[
  {title: "Drinks", header: "header1", item: "Blue Moon"},
  {title: "Drinks", header: "header1", item: "Blue Moon"},
  {title: "Drinks", header: "header2", item: "Blue Moon"}
]

const result = list.reduce((acc, curr) => {
  if(!acc[curr.header]) 
    acc[curr.header] = [];
  
  acc[curr.header].push(curr);
  return acc;
},{});

console.log(result)
/*
Object.keys(res).forEach(key=>{
  let curr=res[key];
      <div className={style.menuItemTitle}>{key}</div>
        {curr.map((item, index) => (
          <div className={style.menuHeader}>{item.header}</div>
          <div className={style.menuItem}>{item.item}</div>
        ))}
})
*/

      
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>

5 Comments

This is close to what I want, but I want this done in a mapping function.
see the commented code, it should be something like this
upvote the answer and mark it as solved if this solution was useful for you. thanks :)
This just gives an error saying res is not defined
replace it with result, sorry it was a typo.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.