'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 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.
Solution 1:[1]
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.
Solution 2:[2]
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; }
Solution 3:[3]
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')
});
Solution 4:[4]
The jsonDatas
definition your shown in the snippet of your question does not match the screenshot, where other values are shown (e.g. 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:
First: convert
jsonDatas
into an array of objects such as those objects contains anitems
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 thesingleItem
array.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 theitems
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)
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | |
Solution 2 | A1exandr Belan |
Solution 3 | Stoule_dev |
Solution 4 |