Travis
Travis

Reputation: 2245

Javascript Sorting Array in custom order

I am trying to sort an array without it being alphabetical. In my case I want the order of the messages returned to be error, warning and then info. Reading about this at W3 I found a similar example...

They give this example with cars but have changed it too messages for my use case.

var message = [
  {type:"Error", message:"This is an Error"},
  {type:"Info", message:"This is an Info"},
  {type:"Warning" message:"This is a Warning"}
];


function myFunction() {
  message.sort(function(a, b){
    var x = a.type.toLowerCase();
    var y = b.type.toLowerCase();
    if (x < y) {return -1;}
    if (x > y) {return 1;}
    return 0;
  });
}

I thought this was all about scoring the value so I thought this might be right way to do it but it isnt giving me the expected results...

function myFunction() {
  message.sort(function(a, b){
    var x = a.type.toLowerCase();
    var y = b.type.toLowerCase();
    if (x === 'error') {return 1;}
    if (x === 'warning') {return 2;}
    if (x === 'info') {return 3;}
    return 0;
  });
}

Upvotes: 1

Views: 114

Answers (3)

Mr. Polywhirl
Mr. Polywhirl

Reputation: 48610

You should have weights for all your log messages for filtering (and sorting, if that's what you need).

I adopted Java's java.util.logging.Level class to introduced various weights for log messages; depending on their severity.

/**
 * Based on:
 * https://docs.oracle.com/javase/8/docs/api/java/util/logging/Level.html
 */
const LogLevel = {
  OFF     : { value: Number.MAX_VALUE }, 
  ERROR   : { value: 1000             }, // Based on Level.SEVERE
  WARNING : { value: 900              },
  INFO    : { value: 800              },
  DEBUG   : { value: 500              }, // Based on Level.FINE
  ALL     : { value: Number.MIN_VALUE }
};

class LogUtils {
  static sortMesages(messages) {
    return messages.sort(({ type: a }, { type: b }) => {
      if (b == null || LogLevel[b.toUpperCase()] == null) return -1;
      if (a == null || LogLevel[a.toUpperCase()] == null) return 1;
      return LogLevel[b.toUpperCase()].value -
             LogLevel[a.toUpperCase()].value;
    });
  }
}

const logMessages = [
  { type: "Error",   message: "This is an Error"  },
  { type: "Info",    message: "This is an Info"   },
  { type: "Warning", message: "This is a Warning" }
];

console.log(LogUtils.sortMesages(logMessages));
.as-console-wrapper { top: 0; max-height: 100% !important; }

Here are some other implementations of logging weights in third-party JS libraries:

Upvotes: 0

Nina Scholz
Nina Scholz

Reputation: 386604

You could take an object with the wanted order and return the delta of the wanted order in the sorting callback.

For sorting unknown types to the end of the array use a large value.

const 
    order = { error: 1, warning: 2, info: 3, default: Number.MAX_VALUE },
    message = [{ type: '' }, { type: "Error", message: "This is an Error" }, { type: "Info", message: "This is an Info" }, { type: "Warning", message: "This is a Warning" }, { type: '' }];

message.sort(({ type: a }, { type: b }) =>
    (order[a.toLowerCase()] || order.default) - (order[b.toLowerCase()] || order.default)
);

console.log(message);
.as-console-wrapper { max-height: 100% !important; top: 0; }

Upvotes: 0

Majed Badawi
Majed Badawi

Reputation: 28414

You can compare y after each time you compare x:

var message = [
  {type:"Error", message:"This is an Error"},
  {type:"Info", message:"This is an Info"},
  {type:"Warning", message:"This is a Warning"}
];


function myFunction() {
  message.sort(function(a, b){
     var x = a.type.toLowerCase();
     var y = b.type.toLowerCase();
     if (x === 'error') {return -1;}
     else if(y === 'error'){return 1;}
     else if (x === 'warning') {return -1;}
     else if (y === 'warning') {return 1;}
     else if (x === 'info') {return -1;}
     else if (y === 'info') {return 1;}
     return 0;
  });
}

myFunction();
console.log(message);

Upvotes: 1

Related Questions