Reputation: 15464
I have json like below
[
{name:'aa',age:'1Y',address:'Alaska'},
{name:'cc',age:'4Years',address:'California'},
{name:'mm',address:'Texas'}
]
Whenever I sort with name and address it work but it will throw runtime error if I try to sort with age as it is missing on last entry.
This is my attempt
let obj=[
{name:'aa',age:'2y',address:'Alaska'},
{name:'cc',age:'4y',address:'California'},
{name:'bb',address:'Texas'}
]
let field='age'; //work for name and address;
let mode='string';
if(mode!='number'){
console.log (obj.sort((a, b) => a[field].toString().localeCompare(b[field].toString())));
}
else{
console.log(obj.sort((a, b) => a[field] -b[field]))
}
What is the best way to ignore the entry when keys are not present , do I need to have seperate loop to check keys before sorting . Entry with missing keys will be on the bottom.
Ps: Ages are never >10 years from the business logic and they can come in any format like 1,1Y so it is treated as string
Upvotes: 0
Views: 312
Reputation: 33726
Entry with missing keys will be on the bottom
Ask for the current value to decide what will be compared or what will be at the bottom.
let obj=[{name:'aa',age:'2y',address:'Alaska'},{name:'cc',age:'4y',address:'California'},{name:'bb',address:'Texas'}],
field = 'age';
console.log(obj.sort((a, b) => a[field] ? b[field] ? a[field].toString().localeCompare(b[field].toString()) : -1 : 1));
.as-console-wrapper { max-height: 100% !important; top: 0; }
If you want to compare the numbers within this string 10years
or this string 5y
, and so on, use a regex to compare the numbers.
let obj=[{name:'aa',age:'24y',address:'Alaska'},{name:'cc',age:'4years',address:'California'},{name:'bb',address:'Texas'}],
field = 'age';
console.log(obj.sort((a, b) => {
let evaluate = () => {
let aval = a[field].replace(/[^\d]/g, '').trim();
let bval = b[field].replace(/[^\d]/g, '').trim();
return aval !== '' && bval !== '' ? Number(aval) - Number(bval) : a[field].toString().localeCompare(b[field].toString());
};
return a[field] ? b[field] ? evaluate() : -1 : 1
}));
.as-console-wrapper { max-height: 100% !important; top: 0; }
Upvotes: 1
Reputation: 13700
Just in case you're looking for an overkill solution :)
let obj=[
{name: 'aa', age: 25, address: 'Alaska'},
{name: 'cc', age: 24, address: 'California'},
{name: 'mm', address: 'Texas'}
];
let field = 'age';
console.log (obj.sort((a, b) => {
a = a[field];
b = b[field];
let defaultValue = '';
if (typeof a === 'number' || typeof b === 'number') {
defaultValue = 0;
}
a = a || defaultValue;
b = b || defaultValue;
if (typeof a === 'number') {
return a - b;
}
else {
return a.localeCompare(b);
}
}));
This automatically handles either strings or numbers, sorting correctly for each. If you want the no-age entries to sort higher rather than lower than everything else, just change what defaultValue
is set to for numbers to a large number.
Upvotes: 0
Reputation: 12806
Just make sure you either have the value of the object, or return an empty string.
The shortest code path would be
(a[field] || "")
Where you indicate that if a
doesn't have the property, it will treat it as an empty string.
It won't cover for a
being null
though, so if that can happen, you have to check it more carefully still
let obj = [{
name: 'aa',
age: '25',
address: 'Alaska'
},
{
name: 'cc',
age: '25',
address: 'California'
},
{
name: 'bb',
address: 'Texas'
}
]
let field = 'age'; //work for name and address
console.log(obj.sort((a, b) => (a[field] || "").toString().localeCompare((b[field] || "").toString())));
Another way to do this, would be to simply compare the values (note, again, if a
or b
would be null, there might be a problem)
let obj = [{
name: 'aa',
age: 25,
address: 'Alaska'
},
{
name: 'cc',
age: 3,
address: 'California'
},
{
name: 'bb',
address: 'Texas'
}
]
function sortAndPrint( obj, field ) {
console.log(`Sorting by ${field}`);
console.log(obj.sort((a, b) => a[field] > b[field] ) );
}
sortAndPrint(obj, 'name');
sortAndPrint(obj, 'address');
sortAndPrint(obj, 'age');
Upvotes: 4
Reputation: 53
This happens because on the last element you don't have the property age when you're trying to access it with property toString.(it is null with the age key)
Upvotes: 0
Reputation: 2720
let obj=[
{name:'aa',age:'25',address:'Alaska'},
{name:'cc',age:'25',address:'California'},
{name:'bb',address:'Texas'}
]
let field='age'; //work for name and address
const sortFunc = (a, b) => a[field].toString().localeCompare(b[field].toString())
// If you can discard entries without the field
console.log(obj.filter(e => field in e).sort(sortFunc))
// If you cannot
console.log(obj.filter(e => field in e).sort(sortFunc).concat(obj.filter(e => !(field in e))))
Upvotes: 0