Nested Loop through the two array for sort by category

221 Views Asked by At

let arr = [
     {
          name: 'siggaret',
          type: 'tobbako'
     },
     {
          name: 'fanta',
          type: 'liquid'
     },
     {
          name: 'potato',
          type: 'vegetables'
     },
     {
          name: 'tvorog',
          type: 'milk'
     },
     {
          name: 'steak',
          type: 'meat'
     },
     {
          name: 'kent',
          type: 'tobbako'
     },
     {
          name: 'cola',
          type: 'liquid'
     },
     {
          name: 'potato',
          type: 'vegetables'
     },
     {
          name: 'tvorog',
          type: 'milk'
     },
     {
          name: 'steak',
          type: 'meat'
     },
     {
          name: 'sheep',
          type: 'meat'
     }
]

let categories = [
     {
          type: 'vegetables',
          arr: [],
          count: 0
     },
     {
          type: 'tobbako',
          arr: [],
          count: 0
     },
     {
          type: 'liquid',
          arr: [],
          count: 0
     },
     {
          type: 'other',
          arr: [],
          count: 0
     }
]

/*
    
*/


for (let item of arr) {
     for (let category of categories) {
          if(item.type === category.type){
               category.arr.push(item.name)
               category.count++
          } else {
               category.arr.push(item.name)
               category.count++
          }
     }
}

console.log(categories)

There items is not added in others ? What is the problem ?

I try to sort all items by category.

There nested loop is not worked well but I try with for of and there are some problems with sorted.

When I try to sort by item.name and category.type all items' name is added to the all category.

I have two arrays and I need to find the difference between the two and display them in an unordered list.

I can loop through the master array for a single match but I have no clue how to loop through the master list for more than one key value and do it efficiently.

Below is an excerpt of key values from each array:

5

There are 5 best solutions below

0
vanowm On BEST ANSWER

Instead of looping through two arrays, you could convert categories into an object, where category type is a key, so you can just use type as key:

let arr = [
     {
          name: 'siggaret',
          type: 'tobbako'
     },
     {
          name: 'fanta',
          type: 'liquid'
     },
     {
          name: 'potato',
          type: 'vegetables'
     },
     {
          name: 'tvorog',
          type: 'milk'
     },
     {
          name: 'steak',
          type: 'meat'
     },
     {
          name: 'kent',
          type: 'tobbako'
     },
     {
          name: 'cola',
          type: 'liquid'
     },
     {
          name: 'potato',
          type: 'vegetables'
     },
     {
          name: 'tvorog',
          type: 'milk'
     },
     {
          name: 'steak',
          type: 'meat'
     },
     {
          name: 'sheep',
          type: 'meat'
     }
]

let categories = {
     'vegetables': {
          arr: [],
          count: 0
     },
     'tobbako': {
          arr: [],
          count: 0
     },
     'liquid': {
          arr: [],
          count: 0
     },
     'other': {
          arr: [],
          count: 0
     }
}


for (let item of arr) {
  //get category object or fallback to "other"
  const category = categories[item.type] || categories.other;
  category.arr.push(item.name)
  category.count++
}

console.log(categories)

// now we can get an array sorted by count of our categories name
const sortedByCount = Object.keys(categories) //get array of types
  .sort((a,b) => categories[b].count - categories[a].count) // sort by count
  .map(type => type + " = "  + categories[type].count); // append count

console.log("categories sorted by count", sortedByCount);

//or convert it into array w/sorted names
const categoriesArray = Object.keys(categories) //get array of types
  .map(type => //convert types into objects
  {
    const category = Object.assign({}, categories[type]); //clone object
  //  const category = categories[type]; //don't clone object
    category.type = type;

    category.arr = [...category.arr].sort(); //clone array and sort it
  //  category.arr.sort(); //sort array of names without clonning
    return category;
  })
  .sort((a,b) => b.count - a.count); //sort by count
console.log("categories as array sorted by count w / sorted names", categoriesArray);
.as-console-wrapper{top:0;max-height:unset!important;overflow:auto!important;}

1
Max Cruer On

In your code, both branches of the if () { ... } else { ... } run the same code. You should remove the else { ... } branch.

Like this:

for (let item of arr) {
     for (let category of categories) {
          if (item.type === category.type){
               category.arr.push(item.name);
               category.count++;
          }
     }
}
0
Daksh Lohar On

The problem is in the else statement, basically, you don't need the else statement cause if you see the code they both are identical, in your case you are adding items to categories, So remove the else statement:

for (let item of arr){
   for (let category of categories) {
      if(item.type === category.type){
          category.arr.push(item.name);
           category.count++;
        }
     }
  }
1
SwissCheese15 On

Good start. The problem is in your else statement. What happens is that:

else {
    category.arr.push(item.name)
    category.count++
}

triggers too often. Every time a category does not match it is pushed.

How to fix: You need handle the "pushing to "others" part" outside of that loop.

0
PeterKA On

You can use a combination of Object.values() and Array#reduce() methods as follows, and then use sort with map to sort the arrays:

const 
    arr = [ { name: 'siggaret', type: 'tobbako' }, { name: 'fanta', type: 'liquid' }, { name: 'potato', type: 'vegetables' }, { name: 'tvorog', type: 'milk' }, { name: 'steak', type: 'meat' }, { name: 'kent', type: 'tobbako' }, { name: 'cola', type: 'liquid' }, { name: 'potato', type: 'vegetables' }, { name: 'tvorog', type: 'milk' }, { name: 'steak', type: 'meat' }, { name: 'sheep', type: 'meat' } ],
    
    categories = Object.values(
        arr.reduce(
            (acc,{name,type}) => 
              ({
                ...acc,[type]:{
                  type,
                  arr:[...(acc[type] && acc[type]?.arr || []),name],
                  count:(acc[type] && acc[type].count || 0) + 1
                }
              }), {}
        )
    )
    .sort((a,b) => a.type.localeCompare(b.type))
    .map(({type,arr,count}) => ({type,arr:arr.sort((a,b) => a.localeCompare(b)),count}));
    
    console.log( categories );