3

I need some help to sort this data out, i have an array of products and i need to sort and display by settings configuration. The output must have the same order as settings array (index) and if display is true. Thanks in advance. This is what i tryed:

var products = [
    {id: 0, name: 'Chocolate', category: 'Sweet'},
    {id: 1, name: 'Almendras', category: 'Fruit'},
    {id: 2, name: 'Nueces', category: 'Fruit'},
    {id: 3, name: 'Mermelada', category: 'Jam'},
    {id: 4, name: 'Alfajor', category: 'Sweet'},
    {id: 5, name: 'Queso', category: 'UwU'},
    {id: 6, name: 'Arandanos', category: 'Fruit'},
    {id: 7, name: 'Maracuya', category: 'Fruit'}
];

let settings = [
    {
        name: 'Fruit',
        display: true
    },
    {
        name: 'Jam',
        display: false
    },
    {
        name: 'Sweet',
        display: true
    },
    {
        name: 'UwU',
        display: true
    }
]


let group = products.reduce((r, a) => {
      r[a.category] = [...r[a.category] || [], a];
      return r;
    }, {});

let arrangedProducts = Object.keys(group); 

console.log(group);
console.log(arrangedProducts);

This is my expected output:

/*
expected result = [
    [
        {id: 1, name: 'Almendras', category: 'Fruit'}, 
        {id: 2, name: 'Nueces', category: 'Fruit'}, 
        {id: 6, name: 'Arandanos', category: 'Fruit'},
        {id: 7, name: 'Maracuya', category: 'Fruit'}
    ],
    [
        {id: 0, name: 'Chocolate', category: 'Sweet'},
        {id: 4, name: 'Alfajor', category: 'Sweet'}
    ],
    [
        {id: 5, name: 'Queso', category: 'UwU'}
    ]
]
*/

4
  • 1
    I’d say this is “grouping” not sorting. Commented Jan 12, 2021 at 1:44
  • See Group array elements depending on their value and How to group and sort object array? Commented Jan 12, 2021 at 1:49
  • Your settings array is never being used, that might be some part of your problem. Commented Jan 12, 2021 at 1:51
  • You might first want to parse the settings array into an object of {name: display} so that the values are easier to access, or build an index object of {name: index} so you don't have to iterate the array every time to find out whether a particular name should be displayed or not. Commented Jan 12, 2021 at 1:56

3 Answers 3

4

Solution

  1. Making of groups
  2. Apply settings and retrieve the result

const products = [
  { id: 0, name: "Chocolate", category: "Sweet" },
  { id: 1, name: "Almendras", category: "Fruit" },
  { id: 2, name: "Nueces", category: "Fruit" },
  { id: 3, name: "Mermelada", category: "Jam" },
  { id: 4, name: "Alfajor", category: "Sweet" },
  { id: 5, name: "Queso", category: "UwU" },
  { id: 6, name: "Arandanos", category: "Fruit" },
  { id: 7, name: "Maracuya", category: "Fruit" },
];

const productsGroup = products.reduce((r, a) => {
  r[a.category] = [...(r[a.category] || []), a];
  return r;
}, {});

function applySettings(settings) {
  return settings.filter((s) => s.display).map((s) => productsGroup[s.name]);
}

console.log(
  applySettings([
    {
      name: "Fruit",
      display: true,
    },
    {
      name: "Jam",
      display: false,
    },
  ])
);

console.log(
  applySettings([
    {
      name: "Fruit",
      display: true,
    },
    {
      name: "Sweet",
      display: true,
    },
    {
      name: "UwU",
      display: true,
    },
  ])
);

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

4 Comments

Includes 'Jam' results.
@StackSlave adding a filter will help thanks for pointing that out
A good answer should explain why the OP has their issue and how your code fixes it. This is very inefficient because it keeps making copies the accumulator on each reduce loop to create the intermediate group object, then uses filter and map to get the required output.
@RobG sometimes making copies can save lots of processing, again and again, all depends on the scenario, based on the scenario the code can perform best or worst. you are right, a good answer should explain OP. Thanks, I will keep that in mind
1

You can filter your settings list based on the display property and then use Array.map to return a list of objects in products that match the category:

const products = [
    {id: 0, name: 'Chocolate', category: 'Sweet'},
    {id: 1, name: 'Almendras', category: 'Fruit'},
    {id: 2, name: 'Nueces', category: 'Fruit'},
    {id: 3, name: 'Mermelada', category: 'Jam'},
    {id: 4, name: 'Alfajor', category: 'Sweet'},
    {id: 5, name: 'Queso', category: 'UwU'},
    {id: 6, name: 'Arandanos', category: 'Fruit'},
    {id: 7, name: 'Maracuya', category: 'Fruit'}
];

const settings = [
    { name: 'Fruit', display: true },
    { name: 'Jam', display: false },
    { name: 'Sweet', display: true },
    { name: 'UwU', display: true }
];

const result = settings
  .filter(c => c.display)
  .map(c => products.filter(o => o.category == c.name));

console.log(result);

Note that this code does filter the products array for each settings value that has display:true, so may be slow for large arrays. However filter is pretty low overhead and testing with OP's sample data shows this to run 3x the speed of the reduce version; and with a larger products array (99 entries) to run 10x faster.

5 Comments

Cool use of filter, but it runs it once for every element in the filtered settings array so might have performance considerations with large data sets. :-)
@RobG agreed, for big data sets processing the data only once will definitely work better. But I suspect that's a reasonably big number because there should be less overhead in filter compared to reduce.
@RobG fyi, I timed this and the most upvoted answer's code for OPs sample data, and this code runs almost 3x faster
@RobG with a larger products array (99 elements) this code ran more than 10x faster than the other answer
I think it's a good answer (you got my vote!), I just think it needs that caveat. The "most upvoted answer" is code–only so no vote from me.
1

This should be pretty quick, because it continues on to the next iteration without executing the inner loop when display is false:

var products = [
    {id: 0, name: 'Chocolate', category: 'Sweet'},
    {id: 1, name: 'Almendras', category: 'Fruit'},
    {id: 2, name: 'Nueces', category: 'Fruit'},
    {id: 3, name: 'Mermelada', category: 'Jam'},
    {id: 4, name: 'Alfajor', category: 'Sweet'},
    {id: 5, name: 'Queso', category: 'UwU'},
    {id: 6, name: 'Arandanos', category: 'Fruit'},
    {id: 7, name: 'Maracuya', category: 'Fruit'}
];

let settings = [
    {
        name: 'Fruit',
        display: true
    },
    {
        name: 'Jam',
        display: false
    },
    {
        name: 'Sweet',
        display: true
    },
    {
        name: 'UwU',
        display: true
    }
];
function sortProducts(){
  const r = [];
  let i = -1;
  for(let s of settings){
    if(!s.display){
      continue;
    }
    i++;
    for(let o of products){
      if(s.name === o.category){
        if(r[i]){
          r[i].push(o);
        }
        else{
          r.push([o]);
        }
      }
    }
  }
  return r;
}
console.log(sortProducts());

Comments

Your Answer

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

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.