I have a persons
list and I sort it by the column in sortColumn
.
const persons = [{
name: "alireza",
family: "seif",
other: {
age: 28,
rate: 30
}
},
{
name: "sara",
family: "niki",
other: {
age: 15,
rate: 15
}
},
{
name: "fateme",
family: "azizy",
other: {
age: 27,
rate: 35
}
}
];
const sortColumn = {
path: "name",
order: "asc"
};
persons.sort((person1, person2) =>
person1[sortColumn.path] > person2[sortColumn.path] ?
sortColumn.order === "asc" ?
1 :
-1 :
person2[sortColumn.path] > person1[sortColumn.path] ?
sortColumn.order === "asc" ?
-1 :
1 :
0
);
console.log(persons);
If sortColumn.path
is "name"
and order
is "asc"
(or "desc"
), the sort
function works correctly. But how can I sort by "other.age"
?
Thanks.
3 Answers 3
You could take a functin which return a sort function, depending on the sort order.
This sorting function uses another function for getting a value from an object by reducing the splitted path to the value.
const
sortBy = ({ order = 'asc', path }) => order === 'asc'
? (a, b) => ((a, b) => a > b || -(a < b))(getValue(a, path), getValue(b, path))
: (a, b) => ((a, b) => b > a || -(b < a))(getValue(a, path), getValue(b, path)),
getValue = (object, keys) => keys.split('.').reduce((o, k) => o[k], object),
persons = [{ name: "sara", family: "niki", other: { age: 15, rate: 15 } }, { name: "alireza", family: "seif", other: { age: 28, rate: 30 } }, { name: "fateme", family: "azizy", other: { age: 27, rate: 35 } }];
console.log(persons.sort(sortBy({ path: "name", order: "asc" })));
console.log(persons.sort(sortBy({ path: "other.rate", order: "desc" })));
.as-console-wrapper { max-height: 100% !important; top: 0; }
-
thank you. in code
console.log(persons.sort(sortBy({ path: "name", order: "asc" })));
must sort [{name:'alireza'...},{name:'fateme'...},{name:'sara'..}}A.R.SEIF– A.R.SEIF2020年01月18日 06:41:50 +00:00Commented Jan 18, 2020 at 6:41 -
@A.R.SEIF, i see the result in the wanted order.Nina Scholz– Nina Scholz2020年01月18日 09:03:31 +00:00Commented Jan 18, 2020 at 9:03
-
thank you.i am copy code in console browser .and result not equals.thanksA.R.SEIF– A.R.SEIF2020年01月18日 09:37:34 +00:00Commented Jan 18, 2020 at 9:37
-
you may have a problem with console, bcause this is sometimes async to the data. for comparing take
JSON.stringify
and check against.Nina Scholz– Nina Scholz2020年01月18日 09:38:47 +00:00Commented Jan 18, 2020 at 9:38 -
some more to read: stackoverflow.com/questions/23392111/console-log-async-or-syncNina Scholz– Nina Scholz2020年01月18日 09:47:55 +00:00Commented Jan 18, 2020 at 9:47
If you want to do sort by that deep property age
, you can't use sortColumn
exactly as you have... Instead, one option is to modify it by making it an array of properties, like so:
sortColumn = { path:["other","age"], order:"asc" }
This way, you'd also have to modify the sort function - as seen in the example below:
const persons = [
{name:"alireza",family:"seif",other:{age:28,rate:30}},
{name:"fateme",family:"azizy",other:{age:27,rate:35}},
{name:"sara",family:"niki",other:{age:15,rate:15}}
]
const sortColumn = { path:["other","age"], order:"asc" }
persons.sort((person1, person2) =>
person1[sortColumn.path[0]][sortColumn.path[1]] > person2[sortColumn.path[0]][sortColumn.path[1]]
? sortColumn.order === "asc"
? 1
: -1
: person2[sortColumn.path[0]][sortColumn.path[1]] > person1[sortColumn.path[0]][sortColumn.path[1]]
? sortColumn.order === "asc"
? -1
: 1
: 0
);
console.log(persons)
However, this approach doesn't work to sort by "name"
since this sort function sorts your data by some piece of data that is two-layers deep (inside "other"
, then "age"
). Here's a modification you can make to the sort function which lets you sort by any properties, any number of layers deep into your data:
const persons = [
{name:"alireza",family:"seif",other:{age:28,rate:30}},
{name:"fateme",family:"azizy",other:{age:27,rate:35}},
{name:"sara",family:"niki",other:{age:15,rate:15}}
]
const sortColumn = { path:["name"], order:"asc" }
persons.sort((person1, person2) => {
// get array of paths
const sortPaths = sortColumn.path;
// get values to sort by
const val1 = sortPaths.reduce((acc, path) => {
if (acc[path]) return acc[path]
else alert(`can't find prop ${path} in person1`);
}, person1)
const val2 = sortPaths.reduce((acc, path) => {
if (acc[path]) return acc[path]
else alert(`can't find prop ${path} in person2`);
}, person2)
return val1 > val2
? sortColumn.order === "asc"
? 1
: -1
: val2 > val1
? sortColumn.order === "asc"
? -1
: 1
: 0
});
console.log(persons)
https://stackoverflow.com/questions/59792589/sort-object-in-object-by-javascript/59792918#
As you can see in this second snippet, you can now search by a shallow property "name"
by using path: ["name"]
, but if you want to sort by a deep value, just add both properties to the path array like this: path: ["other", "age"]
Hope this helps!
The main thing to do is to make your code expect 'path' be a function that selects a property's value, instead of a string pointing to a property name. That way it's much more flexible.
const sortColumn = {
path: p => p.other.age,
order: 'desc'
};
However, if 'persons' is not the only object you'd like to do this with, you can further abstract such a function for general use with any array, such as this:
function sorter (array, path, order) {
array.sort((a,b) => {
let result =
path(a) > path(b) ? 1
: path(a) < path(b) ? -1
: 0;
if (order === "desc")
result = -result;
return result;
});
}
Use it like this:
sorter(persons, p => p.other.age, 'desc');
Expand and run the snippet below to see it in action:
function sorter (array, path, order) {
array.sort((a,b) => {
let result =
path(a) > path(b) ? 1
: path(a) < path(b) ? -1
: 0;
if (order === "desc")
result = -result;
return result;
});
}
const persons = [
{name: "alireza", family: "seif", other: {age: 28, rate: 30}},
{name: "sara", family: "niki", other: {age: 15, rate: 15}},
{name: "fateme", family: "azizy", other: {age: 27, rate: 35}}
];
// convenience function
let sortAndLog = (array, path, order) => {
sorter(array, path, order);
console.log(array.map(path));
}
sortAndLog(persons, p => p.name, "asc");
sortAndLog(persons, p => p.name, "desc");
sortAndLog(persons, p => p.other.age, "asc");
sortAndLog(persons, p => p.other.age, "desc");