sonEtLumiere
sonEtLumiere

Reputation: 4562

Sort aray of objects by another array of objects reference

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'}
    ]
]
*/

Upvotes: 3

Views: 383

Answers (3)

Nick
Nick

Reputation: 147176

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.

Upvotes: 1

MUHAMMAD ILYAS
MUHAMMAD ILYAS

Reputation: 1450

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,
    },
  ])
);

Upvotes: 4

StackSlave
StackSlave

Reputation: 10627

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());

Upvotes: 1

Related Questions