简体   繁体   中英

Javascript - sort an array of multiple objects of objects

I tried with no success to sort an array of multiple objects of objects.

Here my database:

 var jsonDatas = [ { "type": "Voiture", "items": [ { "name": "Fiat Punto", "description": "Je suis une voiture", "price": 10000, "quantity": 2, }, { "name": "Porsche 911", "description": "Je suis une belle voiture", "price": 80000, "quantity": 0, }, ], }, { "type": "Maison", "items": [ { "name": "Villa sur la plage", "description": "Quelle belle vue", "price": 870000, "quantity": 1, }, { "name": "Maison à la campagne", "description": "Vive le calme", "price": 170000, "quantity": 3, } ], }
I want my datas are ordered by items name (alphabetical order): obtain Fiat, Maison, Porsche, Villa, problem is the type, because it sort first the type then the products

在此处输入图像描述

I tried this for example:

 function sortDatasASC(){ database.forEach(element => element.items.sort((a, b) => (a.name > b.name)? 1: -1)), catalogFiltered();

I tried to create an intermediate array to push items and then reassociate with the type but it doesn't work.

For example, this work for a checkbox who display products if there are on stock, but can't duplicate it for a sorting

 const choiceStock = document.getElementById('stockCheck').addEventListener('change', function () { let datas = []; if (this.checked) { let filter = []; database.forEach(element => filter.push({ 'type': element.type, 'items': element.items.filter(test => test.quantity > 0) }) ); datas = filter; } else { datas = database; } showCatalog(datas); });

If you have any ideas??

Thanks in advance.

Your data is grouped by types but since you want it sorted by name instead of by type/name, I would flatten the structure into an array of objects and then apply the logic as you have above:

const flattened = jsonDatas.reduce((acc, entry) => {
  //since we dont want to lose the type information I'm cloning
  //each item and adding a type property to it.
  const items = entry.items.map(i => ({ ...i, type: entry.type }));
  return acc.concat(items);
}, []);

flattened.sort((a, b) => {
  if (a.name.toLowerCase() === b.name.toLowerCase()) {
    return 0;
  }
  return a.name.toLowerCase() > b.name.toLowerCase() ? -1 : 1;
});

//the type is retained so we can rebuild the structure:
const restructured = flattened.map(item => ({
  type: item.type,
  items: [item],
}));

console.log(flattened);
console.log(restructured);

I'm also making the assumption that you want a case insensitive sort. If that's not the case, go ahead and remove the "toLowerCase" calls.

First you need to make a flat array. To be able to sort by type property, you need to add the type to each element. You can also change the sorting function depending on the property type (strng / number). This is just a simple example: :

 const jsonDatas=[{type:"Voiture",items:[{name:"Fiat Punto",description:"Je suis une voiture",price:1e4,quantity:2},{name:"Porsche 911",description:"Je suis une belle voiture",price:8e4,quantity:0}]},{type:"Maison",items:[{name:"Villa sur la plage",description:"Quelle belle vue",price:87e4,quantity:1},{name:"Maison à la campagne",description:"Vive le calme",price:17e4,quantity:3}]}]; const flatData = jsonDatas.flatMap(({ items, type }) => items.map(item => ({...item, type }))); const sortBy = (arr, property, direction = 'asc') => { if (arr.length === 0) return []; const propertyType = typeof arr.at(0)[property]; const sortCallbacks = { string: (e1, e2) => e1[property].localeCompare(e2[property]), number: (e1, e2) => e1[property] - e2[property], }; const sortedAsc = arr.sort(sortCallbacks[propertyType]); if (direction === 'asc' ) return sortedAsc; return sortedAsc.reverse(); }; console.log(sortBy(flatData, 'name' )); console.log(sortBy(flatData, 'type', 'dsc')); console.log(sortBy(flatData, 'price', 'dsc'));
 .as-console-wrapper { max-height: 100%;important: top; 0; }

I finally find the solution, see below if this can helps some of you:

 function createArrayToSort(database) { let datas = []; database.forEach(element => element.items.forEach(items => datas.push({'type': element.type, 'items': [items]}) )) return datas; }; function sortByName(direction){ let datas = createArrayToSort(database); if(direction == "ASC") { datas.sort((a, b) => (a.items[0].name > b.items[0].name)? 1: -1); } else { datas.sort((a, b) => (b.items[0].name > a.items[0].name)? 1: -1); } showCatalog(datas); }; function sortByPrice(direction){ let datas = createArrayToSort(database); if(direction == "ASC") { datas.sort((a, b) => (a.items[0].price > b.items[0].price)? 1: -1); } else { datas.sort((a, b) => (b.items[0].price > a.items[0].price)? 1: -1); } showCatalog(datas); }; const nameASC = document.getElementById('nameASC').addEventListener('click', function () { sortByName('ASC') });

The jsonDatas definition your shown in the snippet of your question does not match the screenshot, where other values are shown (eg Peugeot 205 as a "type": "Voiture" entry). The presence of that Peugeot 205 value denotes that the complete jsonDatas array contains other objects of the same type ( Voiture or Maison ) apart from the objects you listed.

If that is the way the jsonDatas is structured then, to have it sorted as you want, you would need to do two things:

  1. First: convert jsonDatas into an array of objects such as those objects contains an items array with just one element. That will let you manage the order of the records individually. In my snippet below that would be the result in the singleItem array.

  2. Second: after you have transformed your input into singleItem style array, then you can simply sort that array by the name of the unique item in the items array (that is: .items[0].name ).

Below you can see the working code. I used flatMap and map as these are convenient methods to do the transformation of step #1.

 var jsonDatas = [ { "type": "Voiture", "items": [ { "name": "Fiat Punto", "description": "Je suis une voiture", "price": 10000, "quantity": 2, }, { "name": "Porsche 911", "description": "Je suis une belle voiture", "price": 80000, "quantity": 0, }, ], }, { "type": "Maison", "items": [ { "name": "Villa sur la plage", "description": "Quelle belle vue", "price": 870000, "quantity": 1, }, { "name": "Maison à la campagne", "description": "Vive le calme", "price": 170000, "quantity": 3, } ], } ] var singleItem = jsonDatas.flatMap(t => t.items.map(i => { return { type: t.type, items: [ i ] } })) var sorted = singleItem.sort((a, b) => a.items[0].name.localeCompare(b.items[0].name)) console.log(sorted)

For simple sorting via type is just like be

jsonDatas.sort((a, b) => (a.type > b.type)? 1: -1)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM