I have an Array
people = [
{ "name": "Bob Mike", "nickname": "john" , "points": 5 ) },
{ "name": "Andrea Maria", "nickname": "bob", "points": 5 )}
{ "name": "Larry Kiu", "nickname": "larry", "points": 4 ) }
];
I want to sort it like this
Andrea Maria - 5
Bob Mike - 5
Larry Kiu - 4
I'm not into the Sort Method, I found this little Code, but it only Sorts the Points, not including the ASC from the name field.
people.sort(dynamicSort('name')).sort(dynamicSort('points'));
function dynamicSort(property) {return function(a, b) {
return (a[property] > b[property]) ? -1 : (a[property] < b[property])? 1 : 0;
}}
Edit: Thank you Erazihel
You can first sort by points and then use localeCompare to sort by names.
var people = [
{ "name": "Bob Mike", "nickname": "john" , "points": 5 },
{ "name": "Andrea Maria", "nickname": "bob", "points": 5},
{ "name": "Larry Kiu", "nickname": "larry", "points": 4 }
];
people.sort(function(a, b) {
return b.points - a.points || a.name.localeCompare(b.name)
})
console.log(people)
You can use localeCompare to compare two strings
const people = [
{ name: "Bob Mike", nickname: "john" , points: 5 },
{ name: "Andrea Maria", nickname: "bob", points: 5 },
{ name: "Larry Kiu", nickname: "larry", points: 4 }
];
people.sort(function(a, b) {
return b.points - a.points || a.name.localeCompare(b.name)
});
console.log(people.map(a => a.name + ' - ' + a.points));
What you want is something like this
var people = [
{ "name": "Bob Mike", "nickname": "john" , "points": 5 },
{ "name": "Andrea Maria", "nickname": "bob", "points": 5},
{ "name": "Larry Kiu", "nickname": "larry", "points": 4 }
];
people.sort(compare('name')).sort(compare('points'));
function compare(property){
return function(a, b){
return a[property] <= b[property];
}
}
console.log(people);
the compare function returns a function which would work on the property specified
By keeping the idea of a function for checking a single key of the object for sorting, you could use an array with the keys for sorting with their order and build a new array with the callbacks for using with sort.
In the sort callbak, the functions are invoked until the result value is different from a truthy value, which stops the iteration.
function dynamicSort(key, order) {
return function(a, b) {
return +(order === 'ASC' || -1) * +(a[key] < b[key] && -1 || a[key] > b[key]);
};
}
var people = [{ name: "Bob Mike", nickname: "john" , points: 5 }, { name: "Andrea Maria", nickname: "bob", points: 5 }, { name: "Larry Kiu", nickname: "larry", points: 4 }],
sortBy = [['points', 'DESC'], ['name', 'ASC']].map(a => dynamicSort(...a));
people.sort(function (a, b) {
var v = 0;
sortBy.some(f => v = v || f(a, b));
return v;
});
console.log(people);
.as-console-wrapper { max-height: 100% !important; top: 0; }
Related
I have two arrays like this:
let employees = [
{
"id":"1",
"name" : "John Doe"
},
{
"id":"4",
"name" : "Peter Jones"
},
{
"id":"3",
"name" : "Jack Johnson"
},
{
"id":"2",
"name" : "Ron Morris"
}
]
let salaries = [
{
"employeeId" : "1",
"salary": "1500"
},
{
"employeeId" : "2",
"salary": "150"
},
{
"employeeId" : "3",
"salary": null
},
{
"employeeId" : "4",
"salary": "1780"
}
]
Result should be an exposed function for retrieving employees with their salaries from the server.
Function should support returning employees ascending or descending by salary.
I tried something like this but it does not work:
let result = employees.map(e => ({...e, salary: salaries.filter(({ employeeId }) => employeeId === e.id).sort((a,b) => (a.salary > b.salary) ? 1 : ((b.salary > a.salary) ? -1 : 0))}));
Thanks in advance.
This addresses the broader requirements of making it a function, allowing for a parameter that determined ascending or descending order, and also where to place null values.
let employees = [
{
"id": "1",
"name": "John Doe"
},
{
"id": "4",
"name": "Peter Jones"
},
{
"id": "3",
"name": "Jack Johnson"
},
{
"id": "2",
"name": "Ron Morris"
}
];
let salaries = [
{
"employeeId": "1",
"salary": "1500"
},
{
"employeeId": "2",
"salary": "150"
},
{
"employeeId": "3",
"salary": null
},
{
"employeeId": "4",
"salary": "1780"
}
];
/**
* #param {boolean} true for ascending, false for descending
* #param {number} value to use for nulls to determine where to place them
*/
function combineAndSort(employees, salaries, ascending, nullAs = Number.MAX_VALUE) {
return employees.map((employee) => {
return {
...employee,
salary: parseInt(salaries.find((salary) => salary.employeeId === employee.id)?.salary)
};
}).sort((a, b) => {
const aVal = isNaN(a.salary) ? nullAs : a.salary;
const bVal = isNaN(b.salary) ? nullAs : b.salary;
const diff = aVal - bVal;
return ascending ? diff : -diff;
});
}
console.log(combineAndSort(employees, salaries, true));
I have array of objects with properties.
I would like to sort by status, that is
15, 17 then 16 at last in javascript
For a array of objects , status having value 16
should be placed at last and rest should sort by ascending as the expected output.
How to do in javascript
var result = arrobj.filter(e=>e.details.status !== 16).sort(a, b) => a.status - b.status;
var arrobj = [
{
"id":1,
"name": 'xyz',
"details": {
"job": 'fulltime',
"status": 15
}
},
{
"id":2,
"name": 'abc',
"details": {
"job": 'partime',
"status": 16
}
},
{
"id":3,
"name": 'zen',
"details": {
"job": 'fulltime',
"status": 17
}
},
{
"id":5,
"name": 'abu',
"details": {
"job": 'fulltime',
"status": 16
}
},
{
"id":7,
"name": 'john',
"details": {
"job": 'parttime',
"status": 15
}
},
{
"id":10,
"name": 'jocob',
"details": {
"job": 'fulltime',
"status": 17
}
}
]
Expected Output
[
{
"id":1,
"name": 'xyz',
"details": {
"job": 'fulltime',
"status": 15
}
},
{
"id":7,
"name": 'john',
"details": {
"job": 'parttime',
"status": 15
}
},
{
"id":3,
"name": 'zen',
"details": {
"job": 'fulltime',
"status": 17
}
},
{
"id":10,
"name": 'jocob',
"details": {
"job": 'fulltime',
"status": 17
}
},
{
"id":2,
"name": 'abc',
"details": {
"job": 'partime',
"status": 16
}
},
{
"id":5,
"name": 'abu',
"details": {
"job": 'fulltime',
"status": 16
}
}
]
const results = [...arrobj.filter(ob => ob.details.status !== 16).sort((a,b) => a.details.status - b.details.status), ...arrobj.filter(ob => ob.details.status === 16)]
You mean this?
We can customize sort rules using the compareFn in Array.prototype.sort(compareFn).
Example:
var result = arrobj
.sort((obja, objb) => {
let a = obja.details.status
let b = objb.details.status
if (a == 16) a = Number.MAX_SAFE_INTEGER
if (b == 16) b = Number.MAX_SAFE_INTEGER
return a - b
})
for es5
arrobj.sort((a, b) => {
if (a.details.status === 16) {
return 1;
} else if (b.details.status === 16) {
return -1
} else {
return a.details.status - b.details.status
}
})
From EcmaScript 2019 Array.sort is stable. This mean that you can split that complex sorting into 2 - first by status, then placing all items with status 16 in the back. Not efficient solution
arrobj.sort((first,second) => first.details.status - second.details.status)
.sort((first, second) => (first.details.status === 16) - (second.details.status === 16));
The below will also work for your use case. You were really close though
arrobj.filter(e=>e.details.status !== 16).sort((a, b) => {return a.details.status - b.details.status}).concat(arrobj.filter(e=>e.details.status == 16));
Your sort function is not correct. Try this one. I also add the ability to change the sort order.
// Sort by status
function sortByStatus(array, asc = true) {
let newArray = [...array];
// filter and sort
if (asc) {
newArray = newArray.filter(e => e.details.status !== 16).sort((a, b) => a.details.status > b.details.status && 1 || -1);
} else {
newArray = newArray.filter(e => e.details.status !== 16).sort((a, b) => a.details.status < b.details.status && 1 || -1);
}
return newArray;
}
// merge result
const result = [...sortByStatus(arrobj), arrobj.filter(e => e.details.status === 16)];
var arrobj = [{
"id": 1,
"name": 'xyz',
"details": {
"job": 'fulltime',
"status": 15
}
},
{
"id": 2,
"name": 'abc',
"details": {
"job": 'partime',
"status": 16
}
},
{
"id": 3,
"name": 'zen',
"details": {
"job": 'fulltime',
"status": 17
}
},
{
"id": 5,
"name": 'abu',
"details": {
"job": 'fulltime',
"status": 16
}
},
{
"id": 7,
"name": 'john',
"details": {
"job": 'parttime',
"status": 15
}
},
{
"id": 10,
"name": 'jocob',
"details": {
"job": 'fulltime',
"status": 17
}
}
];
// Sort by status
function sortByStatus(array, asc = true) {
let newArray = [...array];
// filter and sort
if (asc) {
newArray = newArray.filter(e => e.details.status !== 16).sort((a, b) => a.details.status > b.details.status && 1 || -1);
} else {
newArray = newArray.filter(e => e.details.status !== 16).sort((a, b) => a.details.status < b.details.status && 1 || -1);
}
return newArray;
}
// merge result
const result = [...sortByStatus(arrobj), arrobj.filter(e => e.details.status === 16)];
console.log(result);
You had to add .status in the sort function sort()
To place the object with status 16 at the end, I made an seperate array with status 16 and added on the end of the array with everything else.
var result = arrobj.filter(e=>e.details.status !== 16).sort( (a, b) => a.details.status - b.details.status);
result = result.concat(arrobj.filter(e=>e.details.status == 16));
console.log(result)
I have an array of (could be more than this), that has a uid and a timestamp.
My goal is to cycle through an object and if their uid is equal to each other, only keep the object with the greater timestamp.
[
{
"uid":"u55555",
"timestamp":1536273731,
"id":"8a655addf1293b6d780ff6469c0848dd",
"name":"John Doe",
},
{
"uid":"u55555",
"timestamp":1536273831,
"id":"8v8799817981mcmccm89c81282128cm2",
"name":"John Doe",
},
{
"uid":"u1111",
"timestamp":1536253940,
"id":"c8898202n2nu929n2828998228989h2h2",
"name":"Test Testerson",
},
{
"uid":"u55555",
"timestamp":1536274940,
"id":"fb990b1734e4aaea2e39315952e13123",
"name":"John Doe",
},
{
"uid":"u11111",
"timestamp":1538275741,
"id":"99s9hshs88s8g89898899898897a79s",
"name":"Test Testerson",
},
]
Does anyone know how I would do this?
I've been playing around with the following but can't get it just right.
var result = signatures.filter(function (a) {
//logic here
}, Object.create(null));
You could sort the original array by timestamp and then reduce it to only a set of unique uids using sort and reduce.
var data = [{"uid": "u55555","timestamp": 1536273731,"id": "8a655addf1293b6d780ff6469c0848dd","name": "John Doe",}, { "uid": "u55555", "timestamp": 1536273831, "id": "8v8799817981mcmccm89c81282128cm2", "name": "John Doe", }, { "uid": "u1111", "timestamp": 1536253940, "id": "c8898202n2nu929n2828998228989h2h2", "name": "Test Testerson", }, { "uid": "u55555", "timestamp": 1536274940, "id": "fb990b1734e4aaea2e39315952e13123", "name": "John Doe", }, { "uid": "u11111", "timestamp": 1538275741, "id": "99s9hshs88s8g89898899898897a79s", "name": "Test Testerson", }];
var result = data
.sort((a,b) => b.timestamp - a.timestamp) //Sort by timestamp descending
.reduce((a,i) => a.some(n=>n.uid === i.uid) ? a : [...a, i], []); //If item is already accounted for, ignore it
console.log(result);
You can create an object keyed to the guid and loop through your array adding the item to the object if it either isn't already there or the time is smaller. Then just take the values from that object:
let arr = [{"uid":"u55555","timestamp":1536273731,"id":"8a655addf1293b6d780ff6469c0848dd","name":"John Doe",},{"uid":"u55555","timestamp":1536273831,"id":"8v8799817981mcmccm89c81282128cm2","name":"John Doe",},{"uid":"u1111","timestamp":1536253940,"id":"c8898202n2nu929n2828998228989h2h2","name":"Test Testerson",},{"uid":"u55555","timestamp":1536274940,"id":"fb990b1734e4aaea2e39315952e13123","name":"John Doe",},{"uid":"u11111","timestamp":1538275741,"id":"99s9hshs88s8g89898899898897a79s","name":"Test Testerson",},]
let newArr = Object.values(
arr.reduce((obj, item) => {
if (!obj[item.uid] || obj[item.uid].timestamp < item.timestamp)
obj[item.uid] = item
return obj
}, {}))
console.log(newArr)
You could find the object and check the timestamp or add the actual object to the result set.
var array = [{ uid: "u55555", timestamp: 1536273731, id: "8a655addf1293b6d780ff6469c0848dd", name: "John Doe" }, { uid: "u55555", timestamp: 1536273831, id: "8v8799817981mcmccm89c81282128cm2", name: "John Doe" }, { uid: "u1111", timestamp: 1536253940, id: "c8898202n2nu929n2828998228989h2h2", name: "Test Testerson" }, { uid: "u55555", timestamp: 1536274940, id: "fb990b1734e4aaea2e39315952e13123", name: "John Doe" }, { uid: "u11111", timestamp: 1538275741, id: "99s9hshs88s8g89898899898897a79s", name: "Test Testerson" }],
result = array.reduce((r, o) => {
var index = r.findIndex(({ uid }) => uid === o.uid);
if (index === -1) {
return r.concat(o);
}
if (o.timestamp > r[index].timestamp) {
r[index] = o;
}
return r;
}, []);
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
This creates a new Object, which uses keys based on the UID; then populates it with only the last entries. Perhaps not the smallest code possible, but it's a method.
let sorted = {};
let original = [{
"uid": "u55555",
"timestamp": 1536273731,
"id": "8a655addf1293b6d780ff6469c0848dd",
"name": "John Doe",
},
{
"uid": "u55555",
"timestamp": 1536273831,
"id": "8v8799817981mcmccm89c81282128cm2",
"name": "John Doe",
},
{
"uid": "u11111",
"timestamp": 1536253940,
"id": "c8898202n2nu929n2828998228989h2h2",
"name": "Test Testerson",
},
{
"uid": "u55555",
"timestamp": 1536274940,
"id": "fb990b1734e4aaea2e39315952e13123",
"name": "John Doe",
},
{
"uid": "u11111",
"timestamp": 1538275741,
"id": "99s9hshs88s8g89898899898897a79s",
"name": "Test Testerson",
},
];
original.forEach((item) => {
if (sorted[item.uid] == undefined || sorted[item.uid].timestamp < item.timestamp) {
// if key doesn't exist, create it
// if key exists but timestamp is newer, replace it
sorted[item.uid] = {
uid: item.uid,
timestamp: item.timestamp,
id: item.id,
name: item.name
}
}
});
console.log(sorted);
I have a JSON object like below:
[
{
"name": "Robert",
"age":32,
"country": "UK"
},
{
"name": "Prasad",
"age":28,
"country": "India"
},
{
"name": "Benny",
"age":45,
"country": "USA"
},
{
"name": "Robin",
"age":34,
"country": "UK"
},
{
"name": "Bob",
"age":20,
"country": "India"
}
]
I have applied the array sorting for "name" column alone. I want to apply sort for “name” column first and then “age”.
This is how i sort the array by name:
var sort_by = function(field, reverse, primer){
var key = primer ?
function(x) {return primer(x[field])} :
function(x) {return x[field]};
reverse = [-1, 1][+!!reverse];
return function (a, b) {
return a = key(a), b = key(b), reverse * ((a > b) - (b > a));
}
}
Call the sort function:
arrayToSort.sort(
sort_by( “name”, true, function(a){
return a.toUpperCase();
}) );
How can I get the array sorted like below?
[{
"name": "Bob",
"age":20,
"country": "India"
},
{
"name": "Benny",
"age":45,
"country": "USA"
},
{
"name": "Prasad",
"age":28,
"country": "India"
},
{
"name": "Robert",
"age":32,
"country": "UK"
},
{
"name": "Robin",
"age":34,
"country": "UK"
}]
I think what you are looking for is a way to "chain" sort_by(..) calls so as to be able to operate on more than one field.
Below is a slightly modified version of your code. Its pretty much self-explanatory.
arrayToSort = [ ...];
var sort_by = function(field, reverse, primer){
var key = primer ?
function(x) {return primer(x[field]); }:
function(x) {return x[field] };
reverse = [-1, 1][+!!reverse];
return function (a, b) {
a = key(a);
b = key(b);
return a==b ? 0 : reverse * ((a > b) - (b > a));
//^ Return a zero if the two fields are equal!
}
}
var chainSortBy = function(sortByArr) {
return function(a, b) {
for (var i=0; i<sortByArr.length; i++) {
var res = sortByArr[i](a,b);
if (res != 0)
return res; //If the individual sort_by returns a non-zero,
//we found inequality, return the value from the comparator.
}
return 0;
}
}
arrayToSort.sort(
chainSortBy([
sort_by( "name", true, function(a){
return a.toUpperCase();
}),
sort_by("age", true, null)
])
);
console.log(arrayToSort); //Check browser console.
For output: check the JSFiddle
The solution is back to native, just :
function orderByProp(arr,prop){
var order = [], ordered=[];
//create temp ID and Save the real index
for(i=0; i < arr.length;++i){ order.push(arr[i][prop]+"-:-"+i);}
ordered.sort();
for(i=0; i < arr.length;++i){
var val = order.split("-:-");
ordered.push(arr[val[1]]); Get the real array by saved index
}
return ordered;
}
// Apply
var arr = [{
"name": "Bob",
"age":20,
"country": "India"
},
{
"name": "Benny",
"age":45,
"country": "USA"
},
{
"name": "Prasad",
"age":28,
"country": "India"
},
{
"name": "Robert",
"age":32,
"country": "UK"
},
{
"name": "Robin",
"age":34,
"country": "UK"
}];
var sort = orderByProp(arr,"name");
i'm not tested this. but hope it could solve your problems
This is relatively trivial with the Array.sort method by using the || operator, where it will use the second value if the first comparison returns 0, meaning the value was the same:
const data = [
{
"name": "Robert",
"age": 32,
},
{
"name": "David",
"age": 24,
},
{
"name": "Robert",
"age": 28,
},
];
const sortedData = data.sort((a, b) => a.name.localeCompare(b.name) || a.age - b.age);
console.log(sortedData);
Credit for this goes to #NinaScholz for her answer here.
I have the following JSON object in javascript:
var stuff = [{
"id": "20",
"serial": "0/0/19:46,0/0/149:63"
}, {
"id": "8",
"serial": "0/0/151:215,0/0/151:233"
}, {
"id": "54",
"serial": "0/0/151:26,0/0/151:37"
}, {
"id": "22",
"serial": "0/0/155:29,0/0/155:36"
}, {
"id": "4",
"serial": "0/0/151:48,0/0/151:152"
}];
I would like to know how to sort the object by the "serial" field, leaving it like this (taking into account the value of the integers in the serial string):
var stuff = [{
"id": "20",
"serial": "0/0/19:46,0/0/149:63"
}, {
"id": "54",
"serial": "0/0/151:26,0/0/151:37"
}, {
"id": "4",
"serial": "0/0/151:48,0/0/151:152"
}, {
"id": "8",
"serial": "0/0/151:215,0/0/151:233"
}, {
"id": "22",
"serial": "0/0/155:29,0/0/155:36"
}];
Thanks in advance.
This will do it for you:
var normalizer = /[:\/]/g;
function serialCompare(a, b) {
var alist = a.serial.replace(normalizer, ',').split(','),
blist = b.serial.replace(normalizer, ',').split(','),
i = 0, l = alist.length;
while (alist[i] === blist[i] && i < l) {
i += 1;
};
return (parseInt(alist[i], 10) - parseInt(blist[i], 10));
}
sortedstuff = stuff.sort(serialCompare);
// returns array sorted as you asked
See it in a fiddle.
If you are going to be sorting often, or the list is very long, you should consider creating a "normalized" version of the serial value that gets stored in the object. It could be the array as calculated inside the serialCompare function, or it could be the text number parts padded to the same lengths with leading zeroes.
You have an array of objects, which you want to sort by one of their properties. You could very easily do it like this:
stuff.sort(function(a,b) {return a.serial == b.serial ? 0 : a.serial < b.serial ? -1 : 1;});
Alternatively, you could have a more general function:
function sort(input,prop) {
input.sort(function(a,b) {return a[prop] == b[prop] ? 0 : a[prop] < b[prop] ? -1 : 1;});
}
// call with:
sort(stuff,'serial');