0

I have list of objects in the following structure which are already in sorted order by name property in the top level.

 [{
     name: 'name1'
     team: 'team1'
     statuses: [{ time: 'day1', color: 'green', message: 'looks good'}, { time: 'day2', color: 'green', message: 'looks good'}]
    },
    {
     name: 'name2'
     team: 'team2'
     statuses: [{ time: 'day1', color: 'yellow', message: 'mild concern'}, { time: 'day2', color: 'red', message: 'critical issue'}]
    },
    {
     name: 'name3'
     team: 'team3'
     statuses: [{ time: 'day1', color: 'orange', message: 'mild concern'}, { time: 'day2', color: 'orange', message: 'potential issue'}]
    }]

The above list should be sorted with custom sort order(red, orange, green) based on color property of last object in the status list. Expected list contains objects in this order team2, team3, team1, if there are multiple of same color then it should retain sorted of name property at top level.

I tried using reduce function in the following way and combined all of them together, but not getting expected output.

 teams.reduce((r, t) => {
     if(t.statuses[1].color === 'red');
       r.push(t)
    return r;
   }, { [] })
  
   teams.reduce((r, t) => {
     if(t.statuses[1].color === 'orange');
       r.push(t)
    return r;
   }, { [] })

   teams.reduce((r, t) => {
     if(t.statuses[1].color === 'green');
       r.push(t)
    return r;
   }, { [] })
user1614862
  • 3,701
  • 7
  • 29
  • 46
  • Does this answer your question? [Sort array of objects by string property value](https://stackoverflow.com/questions/1129216/sort-array-of-objects-by-string-property-value) – CBroe Aug 13 '20 at 09:19
  • To be able to determine the correct order of two items in your custom comparison callback function (referring to _proper_ sorting, as explained in the mentioned duplicate), you can use `indexOf` on an array that contains your three color values in the correct order. – CBroe Aug 13 '20 at 09:21
  • No, my sorting is very different which can be like anything, for example red, orange, green...etc. There is another level of complexity which is like if it is green and comment is other than "looks good" then it should come before it. – user1614862 Aug 13 '20 at 09:24
  • So what? Implement that part of the comparison logic in your sort callback function as well then. – CBroe Aug 13 '20 at 09:26
  • You forgot in your order color yellow., where should it be? – Sascha Aug 13 '20 at 09:48
  • it should be after orange – user1614862 Aug 13 '20 at 22:12

2 Answers2

2

Use filter on the original-array, for sorting order I use a COLORS-array. I added color "yellow" at the end because it was not mentioned in the sort-criterium, you can handle it to your choice.

Extended:

  • As wished is yellow now sorted between orange and yellow.
  • If it is green and comment is other than "looks good" then it should come at beginning.

let list = [{
     name: 'name1',
     team: 'team1',
     statuses: [{ time: 'day1', color: 'green', message: 'looks good'}, { time: 'day2', color: 'green', message: 'looks good'}]
    },
    {
     name: 'name2',
     team: 'team2',
     statuses: [{ time: 'day1', color: 'yellow', message: 'mild concern'}, { time: 'day2', color: 'red', message: 'critical issue'}]
    },
    {
     name: 'name3',
     team: 'team3',
     statuses: [{ time: 'day1', color: 'orange', message: 'mild concern'}, { time: 'day2', color: 'orange', message: 'potential issue'}]
    },
    {
     name: 'name4',
     team: 'team4',
     statuses: [{ time: 'day1', color: 'yellow', message: 'mild concern'}, { time: 'day2', color: 'green', message: 'potential issue'}]
    }
    ];

const COLORS = ['red', 'orange', 'yellow', 'green'];
const GREEN = COLORS.indexOf('green');
 
let result = list.sort((a,b) => {
    let stata = a.statuses[a.statuses.length-1];
    let statb = b.statuses[b.statuses.length-1];
    let cola = COLORS.indexOf(stata.color);
    let colb = COLORS.indexOf(statb.color);
    if (cola == GREEN && stata.message != 'looks good') {
        return (colb == GREEN && statb.message != 'looks good') ? a.name.localeCompare(b.name) : -1;
    }
    if  (colb == GREEN && statb.message != 'looks good') {
        return 1;
    }
    return (cola < colb) ? -1 : ((cola > colb) ? 1: a.name.localeCompare(b.name));
});
 
console.log(result);
Sascha
  • 4,576
  • 3
  • 13
  • 34
  • it has got more complexity, if it is a green and message is other than "looks good" then those entries should come first alphabetically and the remaining should after which also in alphabetical. – user1614862 Aug 13 '20 at 21:17
  • I extended to your wishes. – Sascha Aug 13 '20 at 22:51
  • thanks, I tried with another sort on first set, but this looks simple, I will try this to see if it gives expected result. – user1614862 Aug 14 '20 at 03:20
1

You could create one object where you define order of colors and then use sort method where you first sort by colors and if the colors are the same then you sort by name

const data = [{"name":"name1","team":"team1","statuses":[{"time":"day1","color":"green","message":"looks good"},{"time":"day2","color":"green","message":"looks good"}]},{"name":"name2","team":"team2","statuses":[{"time":"day1","color":"yellow","message":"mild concern"},{"time":"day2","color":"red","message":"critical issue"}]},{"name":"name3","team":"team3","statuses":[{"time":"day1","color":"orange","message":"mild concern"},{"time":"day2","color":"orange","message":"potential issue"}]}]

const order = {
  red: 1,
  orange: 2,
  green: 3
}

data.sort((a, b) => {
  const aColor = a.statuses.slice(-1)[0].color;
  const bColor = b.statuses.slice(-1)[0].color;
  return order[aColor] - order[bColor] || a.name.localeCompare(b.name)
})

console.log(data)
Nenad Vracar
  • 118,580
  • 15
  • 151
  • 176