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.
CodePudding user response:
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.
CodePudding user response:
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; }
CodePudding user response:
For simple sorting via type is just like be
jsonDatas.sort((a, b) => (a.type > b.type) ? 1 : -1)