0

Currently I have an array that I want to sort by 3 keys. For simplicity, the array looks like this:

bArray = [ 
{StartDate:"Mar 1, 2017", ID:"ABC-001", Serial:"10000", Qty: "1"},
{StartDate:"Jun 3, 2017", ID:"CDE-001", Serial:"10004", Qty: "1"}, 
{StartDate:"Mar 1, 2017", ID:"ABC-002", Serial:"10001", Qty: "3"},
{StartDate:"Apr 2, 2017", ID:"CDE-001", Serial:"10003", Qty: "1"},
{StartDate:"Mar 1, 2017", ID:"ABC-001", Serial:"10002", Qty: "1"},
]

I want to sort by ascending in all 3 keys. First by Date, then by ID, then by Serial.

I managed to get it working for Date and ID, however, when I add Serial comparison in the code, I get unexpected results, where the ID and Serial may have anomalies. For example it may be sorted like this when I run the code:

bArray = [ 
{StartDate:"Mar 1, 2017", ID:"ABC-001", Serial:"10000", Qty: "1"},
{StartDate:"Mar 1, 2017", ID:"ABC-002", Serial:"10001", Qty: "3"},
{StartDate:"Mar 1, 2017", ID:"ABC-001", Serial:"10002", Qty: "1"},
{StartDate:"Apr 2, 2017", ID:"CDE-001", Serial:"10003", Qty: "1"},
{StartDate:"Jun 3, 2017", ID:"CDE-001", Serial:"10004", Qty: "1"} 
]

The second and third lines should be reversed because ID should take precedence over Serial.

My code is as follows:

bArray.sort(function (c,d){
  if (c.StartDate > d.StartDate) { return 1; }
  else if (d.StartDate < c.StartDate) { return -1; }

  if (c.ID > d.ID) { return 1; }
  else if (d.ID < c.ID) { return -1; }

  if (c.Serial > d.Serial) { return 1; }
  else if (d.Serial < c.Serial) { return -1; } 
  else { return 0; }
});

I'd like to also mention that the array I'm sorting is over 100+ lines.

Any insight is much appreciated.

Thanks, Vincent

  • 4
    Do you realize you are sorting dates via strings, not the date? And the Serial is sorting by strings, not numbers. – epascarello May 09 '17 at 15:47
  • Dates work fine - they are Date data types in the real scenario Serial could be a string or a number or a combination of both – Vincent Hoang May 09 '17 at 15:54

2 Answers2

2

Your comparisons are all of the form

if ( c.X > d.X ) { return 1; }
else if ( d.X < c.X ) { return -1; }

This will never return -1; if c.X > d.X, then d.X < c.X, but you will have already returned 1.

Instead, you should have c and d in the same order:

if ( c.X > d.X ) { return 1; }
else if ( c.X < d.X ) { return -1; }
// -------^-----^

(Or you could keep them reversed in the else and use > instead of <.)

T.J. Crowder
  • 1,031,962
  • 187
  • 1,923
  • 1,875
Scott Hunter
  • 48,888
  • 12
  • 60
  • 101
  • 1
    Downvoters: Note that the `c` and `d` in the `else` clause are reversed. Either both clauses should use `>`, or the `c` and `d` should be in the same order in both clauses. – T.J. Crowder May 09 '17 at 15:57
0

To sort by date you should parse dates, then you can use localeCompare for strings and finally change Serial to numbers.

var arr = [ 
{StartDate:"Mar 1, 2017", ID:"ABC-001", Serial:"10000", Qty: "1"},
{StartDate:"Jun 3, 2017", ID:"CDE-001", Serial:"10004", Qty: "1"}, 
{StartDate:"Mar 1, 2017", ID:"ABC-002", Serial:"10001", Qty: "3"},
{StartDate:"Apr 2, 2017", ID:"CDE-001", Serial:"10003", Qty: "1"},
{StartDate:"Mar 1, 2017", ID:"ABC-001", Serial:"10002", Qty: "1"},
]
arr.sort(function(a, b) {
  return Date.parse(a.StartDate) - Date.parse(b.StartDate) ||
    a.ID.localeCompare(b.ID) || +a.Serial - +b.Serial
});

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