This question already has answers here:
Sort array of objects by string property value
(57 answers)
Closed 2 years ago.
I have an array of objects:
array = [
{
name: 'fever',
possibility: '20%',
},
{
name: 'hiv',
possibility: '25%',
},
{
name: 'heart-attack',
possibility: '20%'
},
{
name: 'covid',
possibility: '40%',
},
]
I want to sort out the array of objects using its possibility. The object with higher possibility will be on top and if two or many objects have the same possibility then it will be sorted alphabetically. How can I do that?
Use String.localeCompare() with the numeric option to sort using possibility, but use - (minus) to get descending results. If the comparison returns 0 (equals), use localeCompare again to compare the names:
const array = [{"name":"fever","possibility":"20%"},{"name":"hiv","possibility":"25%"},{"name":"heart-attack","possibility":"20%"},{"name":"covid","possibility":"40%"}]
const result = array.sort((a, b) =>
-a.possibility.localeCompare(b.possibility, undefined, { numeric: true })
||
a.name.localeCompare(b.name)
)
console.log(result)
Maybe not only for this, but you could consider using the library Lodash.
It has a lot of cool features, such as sortBy that does exactly what you need.
_.sortBy(array, ['possibility']);
An additional note, is usually be better to store the possibility field (or any percentage value) with a number from 0 to 1, or at least from 1 to 100 as a number, and then adding the % char when displaying :)
To directly answer your questions, this works:
array.sort((e1, e2) => e1.possibility > e2.possibility ? 1 : -1)
Feel free to swap -1 and 1 to move from ascending to descending.
Try like this:
var array = [
{
name: 'fever',
possibility: '20',
},
{
name: 'hiv',
possibility: '25',
},
{
name: 'heart-attack',
possibility: '20'
},
{
name: 'covid',
possibility: '40',
},
]
function sortArray() {
return array.sort((a, b)=> b.possibility- a.possibility)
}
console.log(sortArray());
Prints:
[{
name: "covid",
possibility: "40"
}, {
name: "hiv",
possibility: "25"
}, {
name: "fever",
possibility: "20"
}, {
name: "heart-attack",
possibility: "20"
}]
Based on answer from here:
How to sort 2 dimensional array by column value?
Pure javascript solution would be :
array.sort((a,b) => a.possibility < b.possibility ? 1 : -1)
which would result in :
0: {name: "covid", possibility: "40%"}
1: {name: "hiv", possibility: "25%"}
2: {name: "heart-attack", possibility: "20%"}
3: {name: "fever", possibility: "20%"}
const array = [
{
name: 'fever',
possibility: '20%',
},
{
name: 'hiv',
possibility: '25%',
},
{
name: 'heart-attack',
possibility: '20%'
},
{
name: 'covid',
possibility: '40%',
},
];
const sorted = array.sort((a, b) => {
if (a.possibility > b.possibility) {
return 1;
}
if (a.possibility < b.possibility) {
return -1;
}
return 0;
});
console.log(sorted);
I've added another array entry just to double test the alphabetical ordering as a backup. Run the snippet and check the result:
let array = [
{
name: 'heart-attack',
possibility: '20%',
},
{
name: 'hiv',
possibility: '25%',
},
{
name: 'fever',
possibility: '20%'
},
{
name: 'covid',
possibility: '40%',
},
{
name: 'aaa',
possibility: '40%',
},
]
function compare( a, b ) {
newA = Number(a.possibility.slice(0, -1))
newB = Number(b.possibility.slice(0, -1))
if ( newA < newB ){
return -1;
} else if ( newA > newB ){
return 1;
} else if ( newA === newB && a.name < b.name){
return -1;
} else if ( newA === newB && a.name > b.name){
return 1;
}
return 0;
}
const sortedArr = array.sort(compare)
console.log( sortedArr )
Related
I have one question. How can I sort array items first by their capacity and then by the first letter of their name? The main idea is first to be sorted by capacity from low to high or high to low and then if two items have the same capacity, those two items to be sorted by the first letter of their name.
Here is a basic code sample from me
myArray.sort((eventA, eventB) => {
if (this.state.sort.highToLow.enabled) {
return eventA.capacity > eventB.capacity ? -1 : 1;
} else if (this.state.sort.lowToHigh.enabled) {
return eventA.capacity > eventB.capacity ? 1 : -1;
} else { return 0; }
})
you can use lodash sortBy method
_.sortBy(myArray, ['capacity', 'name']);
try some thing like this. sort method, check for name when capacity is same.
const data = [
{
name: "z",
capacity: 2,
},
{
name: "b",
capacity: 1,
},
{
name: "a",
capacity: 1,
},
];
data.sort((a, b) => {
if (a.capacity === b.capacity) {
return a.name > b.name ? 1 : -1;
}
return a.capacity - b.capacity;
});
console.log(data);
I have an object of data which I'd like to sort. I'm running the following object through Object.entries(data).map() to display it on my Front-End, but I'd like to maintain a specific order. Right now it seems that the order is somewhat random. I'm using .map to display a number of React components so sorting after the map doesn't seem to be possible.
const data = {
rent: {
value: '100'
},
},
legal: {
value: '300'
},
misc: {
value: '300'
},
horse: {
value: '400'
}
},
};
Ideally rent should be the first item when it's mapped out, and misc should be the last one. I've tried using .sort() but I don't seem to be having any luck.
What is the right way to achieve this? I assume some combination of Object.entries(data).sort().map() but I can't seem to figure it out.
You have to provide a compare function to your sort function, if wishing to use Object.entries:
const data = {
rent: {
value: '100'
},
legal: {
value: '300'
},
misc: {
value: '201'
},
horse: {
value: '400'
}
};
function compare(a, b){
if( a[1].value < b[1].value ){
return -1
} else if( a[1].value > b[1].value ){
return 1;
}
return 0;
}
console.log(Object.entries(data).sort(compare))
The code above becomes much cleaner if the original data structure is an array of objects:
const data = [
{ key: 'rent', value: '100' },
{ key: 'legal', value: '300' },
{ key: 'misc', value: '201' },
{ key: 'horse', value: '400' }
];
let sorted = data.sort(({key:k1, value:v1}, {key:k2, value:v2}) => {
if( v1 < v2 ){
return -1;
} else if( v1 > v2 ){
return 1;
}
return 0;
})
console.log('sorted arr', sorted)
the following will sort them so that rent is first misc is last and the rest are alphabetically
const data = {
rent: {
value: '100'
},
legal: {
value: '300'
},
misc: {
value: '300'
},
horse: {
value: '400'
}
};
function rent_ab_misc(obj=[]){
return Object.entries(obj).sort(([key1], [key2]) => {
if (key1 === 'misc' || key2==='rent') return 1;
if (key1 === 'rent' || key2 === 'misc') return -1;
return key1 > key2
})
}
// useage
const output = rent_ab_misc(data).map(([key,item])=>`<div>${key}:${item.value}</div>`)
console.log(output);
If you need to maintain a consistent order, use an array of objects instead of a single object. The property order of an object is not guaranteed.
const data = [
{ name: 'rent', value: '100' },
{ name: 'legal', value: '300' },
{ name: 'misc', value: '300' },
{ name: 'horse', value:'400' }
];
const sortedData = data.sort((a, b) => {
return a.name < b.name ? -1 : a.name > b.name ? 1 : 0;
});
console.log(sortedData);
I know this question was answered before multiple times.
but i didn't find any solution that helped me out.
I got an array of objects with a Name property. I only want to get the objects with the same name.
How my Array looks like:
[
{
Name: 'test',
coolProperty: 'yeahCool1'
},
{
Name: 'test1',
coolProperty: 'yeahCool2'
},
{
Name: 'test2',
coolProperty: 'yeahCool3'
},
{
Name: 'test3',
coolProperty: 'yeahCool4'
},
{
Name: 'test',
coolProperty: 'yeahCool5'
}
]
so I only want to get:
[
{
Name: 'test',
coolProperty: 'yeahCool1'
},
{
Name: 'test',
coolProperty: 'yeahCool5'
}
]
I hope someone can help me out :)
For an O(N) solution, first reduce the array into an object that counts the number of occurrences of each name, and then filter the input by the occurrence count being 2:
const arr = [
{
Name: 'test',
coolProperty: 'yeahCool1'
},
{
Name: 'test1',
coolProperty: 'yeahCool2'
},
{
Name: 'test2',
coolProperty: 'yeahCool3'
},
{
Name: 'test3',
coolProperty: 'yeahCool4'
},
{
Name: 'test',
coolProperty: 'yeahCool5'
}
];
const counts = arr.reduce((a, { Name }) => {
a[Name] = (a[Name] || 0) + 1;
return a;
}, {});
console.log(arr.filter(({ Name }) => counts[Name] === 2));
You could use reduce() and filter() method to get the required result.
Using filter() method you need to check if length is greater than 2 then need it will be push in new array inside of reduce() method
DEMO
const arr =[{"Name":"test","coolProperty":"yeahCool1"},{"Name":"test1","coolProperty":"yeahCool2"},{"Name":"test2","coolProperty":"yeahCool3"},{"Name":"test3","coolProperty":"yeahCool4"},{"Name":"test","coolProperty":"yeahCool5"}];
let getCount = (name)=>{
return arr.filter(o => o.Name == name).length;
}
console.log(arr.reduce((r,item) => {
let len = getCount(item.Name);
return r.concat(len>1?item:[]);
}, []));
I see that you have already got an answer. So I thought of adding another way using map.
var counts = {};
var repeats = {};
arr.map(i => {
counts[i['Name']] = (counts[i['Name']] || []);
counts[i['Name']].push(i);
if (counts[i['Name']].length > 1) {
repeats[i['Name']] = counts[i['Name']];
}
});
console.log(repeats);
Not the best solution considering the performance. Just wanted to add an alternative method.
Hope it helps!!
I am using Angular2, I would like to sort array of objects based on properties in the object. I need to paginate those objects because of limitation of space. So, I do not want to use Pipe in the context of NgFor. I just would like to implement a sorting function before it rendered into DOM. If someone has some information, could you give some guide? All I found was using PipeTransform. So, I am asking you.
You can use underscorejs _.sortBy method.
Code example:
_.sortBy(arr, function(o) { return o.start.dateTime; })
try array.sort() of JS
Example arr.sort()
var fruit = ['cherries', 'apples', 'bananas'];
fruit.sort(); // ['apples', 'bananas', 'cherries']
Example arr.sort(compareFunction)
var items = [
{ name: 'Edward', value: 21 },
{ name: 'Sharpe', value: 37 },
{ name: 'And', value: 45 },
{ name: 'The', value: -12 },
{ name: 'Magnetic', value: 13 },
{ name: 'Zeros', value: 37 }
];
// sort by value
items.sort(function (a, b) {
return a.value - b.value;
});
// sort by name
items.sort(function(a, b) {
var nameA = a.name.toUpperCase(); // ignore upper and lowercase
var nameB = b.name.toUpperCase(); // ignore upper and lowercase
if (nameA < nameB) {
return -1;
}
if (nameA > nameB) {
return 1;
}
// names must be equal
return 0;
});
Updated example, as it didn't match to the object structure which was given in the post
There is an array, which has multiple objects like this:
{
text: text,
elements: [
{
id: id,
page: pageNumber
}
]
}
Now I need to sort the content in two ways:
Sort all array elements by the text-field
I would do like this:
array.sort(function(a,b) {
if (a.text < b.text) return -1;
if (a.text > b.text) return 1;
return 0;
});
The content of the nested elements-array should also be sorted by the page-field.
I don't know how to sort an array, which is nested in the objects... Unfortunately it gets more difficult as the elements are strings, but represent some page numbers. So how can I sort these data in a correct way, as elements could look like 123 or 23-34? And in the case 123-125, 23-34, the last element should be the first.
Example
[
{
text: 'Some text',
elements: [
{ id: 1, pages: '45-67' },
{ id: 2, pages: '12-34' }
]
},
{
text: 'Another text',
elements: [
{ id: 3, pages: '12-34' }
]
}
]
Should be sorted to:
[
{
text: 'Another text',
elements: [
{ id: 3, pages: '12-34' }
]
},
{
text: 'Some text',
elements: [
{ id: 2, pages: '12-34' },
{ id: 1, pages: '45-67' }
]
},
]
So the object order has changed, as A is before S and the order of the page elements in the (now) second object are ordered the other way round.
For the first part, you could use the power of String#localeCompare. And use for the page array another sort function with splitting the string.
var array = [{ id: 1, text: 'Some text', elements: [{ id: 1, pages: '45-67' }, { id: 2, pages: '12-34' }, { id: 4, pages: '12-5' }, { id: 5, pages: '12' }] }, { id: 3, text: 'Another text', elements: [{ id: 3, pages: '12-34' }] }];
array.sort(function (a, b) {
return a.text.localeCompare(b.text);
});
array.forEach(function (el) {
el.elements.sort(function (a, b) {
var aa = a.pages.split('-'),
bb = b.pages.split('-');
return aa[0] - bb[0] || (aa[1] || 0) - (bb[1] || 0);
});
});
console.log(array);
The problem is not a difficult one, as the author has already broken down the problem into smaller chunks. For instance - you mentioned sort the text first and then the nested property (pages), which you are having trouble with.
Your use case is easier as we know you are dealing with pages, so the page numbers will be consistent. E.g. It is unlikely to have entry like '10-20' and '10-15', well if they do then my code below will have to expand a bit to handle this sort of situation.
Otherwise what I have done below is to split the string entry using the - character as delimeter to get a fromPage and toPage parameter. Then using the fromPage we do the usual compare in the sort function to determine who is smaller.
Once that is sorted, then I sort the outer items which you already got a solution for it.
Solution:
// Sort the nested properties first - in this instance it will be page
example.forEach(item => {
item.pages.sort(function (a, b) {
aFromPage = a.split('-')[0];
bFromPage = b.split('-')[0];
// Assuming from page number is unique, if it is not unique then the ToPage number can be
// used for comparison also.
return (aFromPage < bFromPage) ? -1 : 1;
})
});
// Handle the outer item
example.sort(function(a,b) {
if (a.text < b.text) return -1;
if (a.text > b.text) return 1;
return 0;
});
console.log(JSON.stringify(example));
Output:
[
{
"id" : 3,
"text" : "Another text",
"pages":
[
"1-11",
"12-34",
"35-100"
]
},
{
"id" : 1,
"text" : "Some text",
"pages":
[
"12-34",
"35-44",
"45-67",
"68-100"
]
}
]
there is a way to sort element.
function transElement () {
return parseInt(s.split('-')[0], 10);
}
elements.sort(function (a, b) {
return transElement(b) - transElement(a);
});