Mark
Mark

Reputation: 5088

Complex sort of array of objects

I have a variable and array of objects e.g:

var selectedName = 'fff';

[{
    percentage: Math.round(percentage),
    count: count,
    name: 'bbb',
    index: 11,
},
{
    percentage: Math.round(percentage),
    count: 200,
    name: 'aaa',
    index: 2,
},
{
    percentage: Math.round(percentage),
    count: 400,
    name: 'All',
    index: 7,
},
{
    percentage: Math.round(percentage),
    count: count,
    name: 'fff',
    index: 8,
},
{
    percentage: Math.round(percentage),
    count: count,
    name: 'ccc',
    index: 3,
}],

I want to sort these as follows: the object which has the name 'All' should always be first. The next object should be the one with the name that matches selectedName, in this case 'fff'. And then the rest of the objects should be ordered by ascending order of their 'index' property.

Is this possible in one Array.sort() method?

Upvotes: 1

Views: 93

Answers (4)

kind user
kind user

Reputation: 41893

You can use a helping object holding the priority of each element. In your particular case, the highest priority has All value.

So firstly we sort the values with higher priority (All, 'fff') and when it's done, we sort the rest by the index value.

Note: Since we are sorting it by ascending order the priority values have to be negative. If we would sort it by a descending order (b - a), they would be positive.

var arr = [{percentage:Math.round("percentage"),count:"count",name:"bbb",index:11},{percentage:Math.round("percentage"),count:200,name:"aaa",index:2},{percentage:Math.round("percentage"),count:400,name:"All",index:7},{percentage:Math.round("percentage"),count:"count",name:"fff",index:8},{percentage:Math.round("percentage"),count:"count",name:"ccc",index:3}],
    selectedName = 'fff',

result = arr.sort(function(a,b){
  var order = {All: -2, [selectedName]: -1, default: 0};
  return (order[a.name] || order.default) - (order[b.name] || order.default) || a.index - b.index;
});

console.log(result);

Upvotes: 1

Rajesh
Rajesh

Reputation: 24925

You can try something like this:

Idea

  • (a.name !== priorityName) will yield a boolean value. When you use -(minus) operator on them, it is converted to numeric value(true: 1, false: 0).
  • So if both are neither of priority, both will yield 1 and output will be 0, which is falsey in JS.
  • Failure of previous expression will call current expression and would loop till last expression

var selectedName = 'fff';
var priorityName = "All";
var percentage = 50.4, count= 0;
var data=[{percentage:Math.round(percentage),count:count,name:"bbb",index:11},{percentage:Math.round(percentage),count:200,name:"aaa",index:2},{percentage:Math.round(percentage),count:400,name:"All",index:7},{percentage:Math.round(percentage),count:count,name:"fff",index:8},{percentage:Math.round(percentage),count:count,name:"ccc",index:3}];
  
data.sort(function(a,b){
  return  (a.name !== priorityName) - (b.name !== priorityName) ||
          (a.name !== selectedName) - (b.name !== selectedName) ||
           a.index - b.index;
})

console.log(data)

Upvotes: 1

kemiller2002
kemiller2002

Reputation: 115498

Sure you can do it like so:

var selectedName = 'fff';
var percentage = 23;
var count = 3;

var data=[{percentage:Math.round(percentage),count:count,name:"bbb",index:11},{percentage:Math.round(percentage),count:200,name:"aaa",index:2},{percentage:Math.round(percentage),count:400,name:"All",index:7},{percentage:Math.round(percentage),count:count,name:"fff",index:8},{percentage:Math.round(percentage),count:count,name:"ccc",index:3}];


function sortItems(a, b) {
  if (a.name === 'All') {
    return -1
  }

  if (b.name === 'All') {
    return 1;
  }

  if (a.name === selectedName) {
    return -1
  }

  if (b.name === selectedName) {
    return 1
  }

  return a.index - b.index;

}


console.log(items.sort(sortItems));

Upvotes: 1

rpadovani
rpadovani

Reputation: 7360

Yes, here an example:

var selectedName = 'fff';
let percentage = 1;
let count = 2;
var data=[{percentage:Math.round(percentage),count:count,name:"bbb",index:11},{percentage:Math.round(percentage),count:200,name:"aaa",index:2},{percentage:Math.round(percentage),count:400,name:"All",index:7},{percentage:Math.round(percentage),count:count,name:"fff",index:8},{percentage:Math.round(percentage),count:count,name:"ccc",index:3}];

arr.sort((i, j) => {
    if (i.name === j.name && (i.name === 'All' || i.name === selectedName)) return 0;

    if (i.name === 'All') return -1;
    if (j.name === 'All') return 1;
    
    if (i.name === selectedName) return -1;
    if (j.name === selectedName) return 1;
    
    if (i.index < j.index) return -1;
    if (i.index > j.index) return 1;
    return 0;
})

console.log(arr)

Upvotes: 4

Related Questions