This question already has answers here:
Sort array of objects by string property value
(57 answers)
Closed 3 years ago.
I am trying to sort the array of objects based on change property.
Below is the sort function, the strange part is the price when below 100 it's not getting sorted properly. I want the array of objects to be sorted by asc or desc order by either change or name.
const data = [{
"id": 74368,
"account": "Gerald Wehner",
"change": "186.00"
},
{
"id": 55998,
"account": "Augusta Koelpin",
"change": "277.00"
},
{
"id": 3044,
"account": "Austyn Bradtke",
"change": "473.00"
},
{
"id": 50305,
"account": "Lesly Boyer",
"change": "56.00"
},
{
"id": 20324,
"account": "Marietta Lynch",
"change": "707.00"
},
{
"id": 40233,
"account": "Eriberto Haley",
"change": "923.00"
}
];
sort = (arr, field, order, cond) => {
const fn = cond ?
function(x) {
return cond(x[field])
} :
function(x) {
return x[field]
};
order = !order ? 1 : -1;
return arr.sort(function(a, b) {
return a = fn(a), b = fn(b), order * ((a > b) - (b > a));
})
}
console.log(sort(data, 'change', true, false))
You're comparing the values as text instead of numbers.
const data = [{
"id": 74368,
"account": "Gerald Wehner",
"change": "186.00"
},
{
"id": 55998,
"account": "Augusta Koelpin",
"change": "277.00"
},
{
"id": 3044,
"account": "Austyn Bradtke",
"change": "473.00"
},
{
"id": 50305,
"account": "Lesly Boyer",
"change": "56.00"
},
{
"id": 20324,
"account": "Marietta Lynch",
"change": "707.00"
},
{
"id": 40233,
"account": "Eriberto Haley",
"change": "923.00"
}
];
sort = (arr, field, order, cond) => {
const fn = cond ?
function(x) {
return Number(cond(x[field]));
} :
function(x) {
return Number(x[field]);
};
order = !order ? 1 : -1;
return arr.sort(function(a, b) {
return a = fn(a), b = fn(b), order * ((a > b) - (b > a));
})
}
console.log(sort(data, 'change', true, false))
Note that, in the case of strings like "account" this sorts by first name, then last name:
const data=[{id:74368,account:"Gerald Wehner",change:"186.00"},{id:55998,account:"Augusta Koelpin",change:"277.00"},{id:3044,account:"Austyn Bradtke",change:"473.00"},{id:50305,account:"Lesly Boyer",change:"56.00"},{id:20324,account:"Marietta Lynch",change:"707.00"},{id:40233,account:"Eriberto Haley",change:"923.00"}]
function sortData(dir, prop){
return data.sort((a,b) => {
let x = dir === "ASC" ? a : b
let y = dir === "ASC" ? b : a
if(isNaN(data[0][prop])){
return x[prop].localeCompare(y[prop])
}else{
return x[prop] - y[prop]
}
})
}
console.log(sortData("ASC", "change"))
Update
Added functionality for new format (see comments)
const data=[{id:74368,account:"Gerald Wehner",change:" GeraldWehner - 186"},{id:55998,account:"AugustaKoelpin",change:"AugustaKoelpin - 999"}]
function sortData(dir, prop){
return data.sort((a,b) => {
let x = dir === "ASC" ? a : b
let y = dir === "ASC" ? b : a
let exProp = data[0][prop]
if(isNaN(exProp)){
if( exProp.indexOf("-") > -1 && !isNaN( exProp.split("-")[1].trim() ) ){
let xTest = x[prop].split("-")[1].trim()
let yTest = y[prop].split("-")[1].trim()
return xTest - yTest
}
return x[prop].localeCompare(y[prop])
}else{
return x[prop] - y[prop]
}
})
}
console.log(sortData("ASC", "change"))
Related
Here is an example
testWidgetOrderSort = [
{ "_id": "name", "order": 1 },
{ "_id": "is", "order": 2 },
{ "_id": "my", "order": 0 },
{ "_id": "oh I would be very first" },
{ "_id": "adam", "order": 3 }
]
Here for the the object { "_id": "oh I would be very first" } does not have the property order so it should come first.
And then the rest of the objects should be sorted according to the property "order"
So after sorting it should be,
output= [ { _id: 'oh I would be very first' },
{ _id: 'my', order: 0 },
{ _id: 'name', order: 1 },
{ _id: 'is', order: 2 },
{ _id: 'adam', order: 3 } ]
Logic is basic array sorting logic.
If both a.order and b.order are defined return 1 or -1 depending on the largest value.
If either one of them is undefined return 1 or -1 depending on the defined value.
Please Note: The value 1 and -1 determines the relative position between the two nodes. Returning 1 places a after b and -1 places a before b.
const testWidgetOrderSort = [
{ "_id": "name", "order": 1 },
{ "_id": "is", "order": 2 },
{ "_id": "my", "order": 0 },
{ "_id": "oh I would be very first" },
{ "_id": "adam", "order": 3 }
];
const output = testWidgetOrderSort.sort((a, b) => {
if( a.order !== undefined && b.order !== undefined ) {
return a.order > b.order ? 1 : -1;
} else {
return a.order !== undefined ? 1 : -1
}
});
console.log(output);
I came up with something like this:
const test = [
{ "_id": "name", "order": 1 },
{ "_id": "is", "order": 2 },
{ "_id": "my", "order": 0 },
{ "_id": "oh I would be very first" },
{ "_id": "adam", "order": 3 }
];
const x = test.sort((a, b) => {
const [STAY, SWAP] = [-1, 1];
if (!a.hasOwnProperty('order')) { return STAY; }
if (!b.hasOwnProperty('order')) { return SWAP; }
return a.order - b.order;
});
console.log(x);
You just have to pass the custom comparator function
if (!("order" in a)) return -1;
if (!("order" in b)) return 1;
else return a.order - b.order;
1) return -1 if property order doesn't exist in a.
2) return 1 if property order doesn't exist in b.
3) if both the object has order property then just sort in ascending order.
const arr = [
{ _id: "name", order: 1 },
{ _id: "is", order: 2 },
{ _id: "my", order: 0 },
{ _id: "oh I would be very first" },
{ _id: "adam", order: 3 },
];
const result = arr.sort((a, b) => {
if (!("order" in a)) return -1;
if (!("order" in b)) return 1;
else return a.order - b.order;
});
console.log(result);
If you don't care about the performance too much, the below should be fine,
const testWidgetOrderSort = [
{ "_id": "name", "order": 1 },
{ "_id": "is", "order": 2 },
{ "_id": "my", "order": 0 },
{ "_id": "oh I would be very first" },
{ "_id": "adam", "order": 3 }
];
const finalArr = testWidgetOrderSort.filter(a => typeof a.order === "undefined");
const sortedArrWithOrderItems = testWidgetOrderSort.filter(a => typeof a.order !== "undefined").sort((a,b) => (a.order > b.order ? 1 : -1));
finalArr.push(...sortedArrWithOrderItems);
console.log(finalArr);
Note: Personally I would recommend going with #Nitheesh or #decpk solution, it is more clean and performance wise better. My solution is just to give another solution for the problem
This question already has answers here:
How to deep merge instead of shallow merge?
(47 answers)
Closed 2 years ago.
let x = { "1": { "id": 1 }, "2": { "id": 1, "key": "value" } }
let y = { "2": { "id": 2 } }
let z = {
...x,
...y,
}
console.log(z);
I would like to have an output of
{ "1": { "id": 1 }, "2": { "id": 2, "key": "value" } }
the Current output is
{ "1": { "id": 1 }, "2": { "id": 2 } }
Keys will only be applies the the first level, you must go down a level.
let x = { "1": { "id": 1 }, "2": { "id": 1, "key": "value" } }
let y = { "2": { "id": 2 } }
let z = { ...x, ...y } // outer
for (let k in z) z[k] = { ...x[k], ...y[k] } // inner
console.log(z)
.as-console-wrapper { top: 0; max-height: 100% !important; }
<!-- Expected
{
"1": {
"id": 1
},
"2": {
"id": 2,
"key": "value"
}
}
-->
A more robust approach
I borrowed Lewis' example for deep-merging multiple objects and converted it to a plugin.
// Based on: https://stackoverflow.com/a/55736757/1762224
const ObjectUtils = (() => {
const { keys, freeze } = Object // sym-links
let __isObject, __merge, __coalesceByKey, __deepMerge // fwd declaration
__isObject = a => typeof a === "object" && !Array.isArray(a)
__merge = (a, b) =>
__isObject(a) && __isObject(b)
? __deepMerge(a, b)
: __isObject(a) && !__isObject(b)
? a : b
__coalesceByKey = src => (acc, key) =>
(acc[key] && src[key]
? (acc[key] = __merge(acc[key], src[key]))
: (acc[key] = src[key])) && acc
__deepMerge = (target, ...sources) =>
sources.reduce(
(acc, src) => keys(src).reduce(__coalesceByKey(src), acc), target
)
return freeze({ isObject : __isObject, deepMerge : __deepMerge })
})()
let x = { "1": { "id": 1 }, "2": { "id": 1, "key": "value" } }
let y = { "2": { "id": 2 } }
console.log(ObjectUtils.deepMerge({}, x, y));
.as-console-wrapper { top: 0; max-height: 100% !important; }
I would use lodash:
_.merge(object, [sources])
This method is like _.assign except that it recursively merges own and inherited enumerable string keyed properties of source objects into the destination object. Source properties that resolve to undefined are skipped if a destination value exists. Array and plain object properties are merged recursively. Other objects and value types are overridden by assignment. Source objects are applied from left to right. Subsequent sources overwrite property assignments of previous sources.
Here is my solution:
let x = { "1": { id: 1 }, "2": { id: 1, key: "value" } };
let y = { "2": { id: 2 } };
let z = {};
for (let [key, value] of Object.entries(x)) {
if (y.hasOwnProperty(key)) {
z[key] = {
...value,
id: y[key].id
};
} else {
z[key] = value;
}
}
console.log(z);
This question already has answers here:
Sort an array of object by a property (with custom order, not alphabetically)
(7 answers)
Closed 5 years ago.
I got an array that I want to sort depending on a value on my object.
My array looks like this:
[
{
"name": "Ricard Blidstrand",
"number": "5",
"position": "b"
},
{
"name": "Gustaf Thorell",
"number": "12",
"position": "fw"
},
{
"name": "Rasmus Bengtsson",
"number": "13",
"position": "mv"
}
]
I want to order according to the position-key in this order:
mv > b > fw
Do I need to write it like, or am I wrong?
if(a === "b" && b === "b") {
return 0;
} else if (a === "b" && b === "mv") {
return 1;
}
You need to specify priority array first.
var priority = [ "mv", "b", "fw"];
Now sort your array based on this as
arr.sort( ( a, b ) => priority.indexOf( a.position ) - priority.indexOf( b.position ) );
Demo
var arr = [{
"name": "Ricard Blidstrand",
"number": "5",
"position": "b"
},
{
"name": "Gustaf Thorell",
"number": "12",
"position": "fw"
},
{
"name": "Rasmus Bengtsson",
"number": "13",
"position": "mv"
}
];
var priority = [ "mv", "b", "fw"];
arr.sort( ( a, b ) => priority.indexOf( a.position ) - priority.indexOf( b.position ) );
console.log(arr);
Create an order object, and assign a value for each position. Sort by taking the order value from the object by the object's position:
var arr = [{"name":"Ricard Blidstrand","number":"5","position":"b"},{"name":"Gustaf Thorell","number":"12","position":"fw"},{"name":"Rasmus Bengtsson","number":"13","position":"mv"}]
var order = { mv: 0, b: 1, fw: 2 }
arr.sort(function(a, b) {
return order[a.position] - order[b.position]
})
console.log(arr)
I have an array of objects something like this
var itemArray = [
{
"name": "name1",
"flag": true,
},
{
"name": "name1",
"flag": false,
},
{
"name": "name2",
"flag": false,
},
{
"name": "name3",
"flag": true,
}
];
I am already sorting this by the name key using the following:
var sortedItems = sortByKey(itemArray, "name");
function sortByKey(array, key) {
return array.sort(function(a, b) {
var x = a[key];
var y = b[key];
return ((x < y) ? -1 : ((x > y) ? 1 : 0));
});
How do i also sort it by the flag key alphabetically so the false flags appear before the true flags? (I can use a string instead of boolean on the flag property if this makes it simpler)
To clarify, what I am looking for is an array which would be returned like this for example:
[
{ name: "name_a", flag: false },
{ name: "name_a", flag: true },
{ name: "name_b", flag: false },
{ name: "name_b", flag: true},
{ name: "name_c", flag: true},
{ name: "name_d", flag: false},
]
var sortedItems = sortByKey(itemArray, "name");
function sortByKey(array, key) {
return array.sort(function(a, b) {
if(a[key] == b[key]) {
return (a['flag'] ? -1 : 1);
} else {
var x = a[key];
var y = b[key];
return x.localeCompare(y);
}
});
var sortedItems = sortByKey(itemArray, "name");
function sortByKey(array, key) {
return array.sort(function(a, b) {
if(a['flag'] == f['flag']) {
var x = a[key];
var y = b[key];
return ((x < y) ? -1 : ((x > y) ? 1 : 0));
} else {
return (a['flag'] ? -1 : 1);
}
});
You could use a proper callback, sort first by flag and if equal then by name.
var itemArray = [{ "name": "name1", "flag": true, }, { "name": "name1", "flag": false, }, { "name": "name2", "flag": false, }, { "name": "name3", "flag": true, }];
itemArray.sort(function (a, b) {
return a.name.localeCompare(b.name) || a.flag - b.flag;
}),
console.log(itemArray);
I have a list of objects where I want to sort the objects based on a field I know I can use sort methods. When the comparing field have null values, sorting is not happening, how to fix this issue?
http://jsfiddle.net/mailtoshebin/kv8hp/
var arrOfObj = [
{
"Name": "Zak",
"Age": 25
},
{
"Name": "Adel",
"Age": 38
},
{
"Name": null,
"Age": 38
},
{
"Name": "Yori",
"Age": 28
}
];
sortArrOfObjectsByParam(arrOfObj, "Name");
alert("ASCENDING: " + arrOfObj[0].Name + ", " + arrOfObj[1].Name + ", " + arrOfObj[2].Name);
function sortArrOfObjectsByParam(arrToSort , strObjParamToSortBy ) {
if(sortAscending == undefined) sortAscending = true; // default to true
if(sortAscending) {
arrToSort.sort(function (a, b) {
return a[strObjParamToSortBy] > b[strObjParamToSortBy];
});
}
else {
arrToSort.sort(function (a, b) {
return a[strObjParamToSortBy] < b[strObjParamToSortBy];
});
}
}
you can deal with the null values inside the comp func:
arrToSort.sort(function (a, b) {
if (a[strObjParamToSortBy]==null) return 1
if (b[strObjParamToSortBy]==null) return 0
return a[strObjParamToSortBy] > b[strObjParamToSortBy];
});