4

I have an array that looks like this:

order = [ "foo", "bar", "baz" ];

This array contains the attribute values I would like to sort my array of objects by. I want to sort the data so that all the objects with name "foo" are first, then "bar", then "baz". My array of objects looks something like this:

data = [ 
    {name: "foo", score: 8},
    {name: "baz", score: 4},
    {name: "baz", score: 9}, 
    {name: "foo", score: 6}, 
    {name: "bar", score: 9} 
];

I want to outcome of the data order to look like this, the array is ordered by name but also by score desc when the names are the same:

sortedData =  [ 
    {name: "foo", score: 8},
    {name: "foo", score: 6},  
    {name: "bar", score: 9},
    {name: "baz", score: 9},
    {name: "baz", score: 4} 
];

Here is the code I have tried so far:

order.forEach(name => {
      sortedData = [...this.data].sort(function(obj1, obj2) {
            return (
              -(obj1.name)  || obj2.score < obj1.score
            );
          });
        });
console.log(sortedData);
Team Cafe
  • 301
  • 1
  • 4
  • 6
  • If you don't want the original array to be mutated and instead a new sorted array to be returned then please check my answer also! – Fullstack Guy Mar 24 '19 at 17:43

3 Answers3

1

Use the index to sort based on the order, to get index you can use Array#indexOf method. To sort based on the number just return the difference.

//  extract object properties for comparing
// return difference of indexes to sort based on that
// in case indexes are same return difference of score(to sort element with same name) 
data.sort(({ name: a, score: as }, { name: b ,score: bs}) => order.indexOf(a) - order.indexOf(b) || bs - as)

let order = ["foo", "bar", "baz"];
let data = [{
    name: "foo",
    score: 8
  },
  {
    name: "baz",
    score: 4
  },
  {
    name: "baz",
    score: 9
  },
  {
    name: "foo",
    score: 6
  },
  {
    name: "bar",
    score: 9
  }
];


data.sort(({ name: a, score : as }, { name: b ,score:bs}) => order.indexOf(a) - order.indexOf(b) || bs - as)

console.log(data)
Pranav C Balan
  • 113,687
  • 23
  • 165
  • 188
1

You can simply use sort and indexOf

let order = [ "foo", "bar", "baz" ];

let data = [ 
    {name: "foo", score: 8},
    {name: "baz", score: 4},
    {name: "baz", score: 9}, 
    {name: "foo", score: 6}, 
    {name: "bar", score: 9} 
];

let op = data.sort((a,b)=> (order.indexOf(a.name) - order.indexOf(b.name)) || b.score - a.score )

console.log(op)
Code Maniac
  • 37,143
  • 5
  • 39
  • 60
0

We can use the array indices in the order array for sorting. Also using object destructuring assignment to get the object keys for comparison. If the first comparison of name key results in equality of the two keys then going for the second criteria of the score key.

In my answer I did not mutate the original array, if that kind of behavior is needed you can check this solution:

const order = [ "foo", "bar", "baz" ];
const data = [ 
    {name: "foo", score: 8},
    {name: "baz", score: 4},
    {name: "baz", score: 9}, 
    {name: "foo", score: 6}, 
    {name: "bar", score: 9} 
];
function sortArray(data, order){
  const sortedArr = Array.from(data).sort(({name: name1, score: score1},{name: name2, score: score2}) =>{
     return name1 === name2 ? score2 - score1 : order.indexOf(name1) - order.indexOf(name2);
  });
  return sortedArr;
}
console.log("***Sorted Array***");
console.log(sortArray(data, order));
console.log("***Original Array***");
console.log(data);
Fullstack Guy
  • 16,368
  • 3
  • 29
  • 44