1

I am trying to sort an array:

var mapped = [{
    wiFi: true,
    megapixel: '20 MP'
},{
    wiFi: false,
    megapixel: '25 MP'
},{
    wiFi: true,
    megapixel: '25 MP'
},{
    wiFi: true,
    megapixel: '21 MP'
}];

I would like to sort it on both properties (wiFi first). This is a really simple version of what I am doing, but the properties can be decided by the user, so I have a function that looks a bit like this:

var fields = ['wiFi', 'megapixel'];

// Sort our mapped array
mapped.sort(function (a, b) {

    // Loop through our properties
    fields.forEach(function (field) {

        // Get our value (skip the first)
        var x = a[field.name];
        var y = b[field.name];

        // Switch on the type
        switch (typeof x) {

            // Boolean
            case "boolean":

                // Return our value
                return x === y ? 0 : x ? -1 : 1;

            // Default
            default:

                // Return our value
                return x === y ? 0 : x < y ? -1 : 1;

        }
    });
});

but my array is not being sorted at all. Does anyone know why?

3
  • 4
    Yes, because you're not actually returning any result from the sort callback - only from the inner forEach callback. Commented Apr 28, 2016 at 10:40
  • You don't need to iterate fields until the end. Stop when you don't return 0. Commented Apr 28, 2016 at 10:46
  • can you post an example? Commented Apr 28, 2016 at 10:48

4 Answers 4

1

Try a manual iteration instead of one that uses an inner function.

mapped.sort(function(a,b) {
    var x, y, i, l = fields.length;
    for( i=0; i<l; i++) {
        x = a[fields[i]];
        y = b[fields[i]];
        if( x === y) continue; // proceed to next field to compare
        switch(typeof x) {
        case "boolean":
            return x ? -1 : 1;
        // could do other things, eg. case "string": return x.localeCompare(y);
        default:
            return x < y ? -1 : 1;
        }
    }
    return 0; // all fields compared equal
});
Sign up to request clarification or add additional context in comments.

Comments

0

You can try to compute rank and based on rank, you can sort values:

logic:

  • For boolean, if true, add 10 in self and remove 10 from other.
  • For others, you can use a generic logic, add 10 in bigger value and reduce 10 from smaller value.
  • Sort based on this rank.

var mapped = [{ wiFi: true, megapixel: '20 MP'}, {  wiFi: false,  megapixel: '25 MP'}, {  wiFi: true,  megapixel: '25 MP'}, {  wiFi: true,  megapixel: '21 MP'}];

var fields = ['wiFi', 'megapixel'];

// Sort our mapped array
mapped.sort(function(a, b) {
  var a_rank = 0;
  var b_rank = 0;
  // Loop through our properties
  fields.forEach(function(field) {

    // Get our value (skip the first)
    var x = a[field];
    var y = b[field];

    // Switch on the type
    switch (typeof x) {
      // Boolean
      case "boolean":
        a_rank += x ? -10 : 10;
        b_rank += y ? -10 : 10;
        break;
        // Default
      default:
        if (x > y) {
          a_rank += 10;
          b_rank -= 10;
        } else if (y > x) {
          a_rank -= 10;
          b_rank += 10
        }
        break;
    }
  });
  return a_rank > b_rank ? 1 : a_rank < b_rank ? -1 : 0
});
document.write("<pre>" + JSON.stringify(mapped,0,4)+ "</pre>")

Comments

0

You can use sort with a helper object.

var mapped = [{ wiFi: true, megapixel: '20 MP' }, { wiFi: false, megapixel: '25 MP' }, { wiFi: true, megapixel: '25 MP' }, { wiFi: true, megapixel: '21 MP' }],
    fields = ['wiFi', 'megapixel'],
    types = {
        wiFi: function (o) { return +!o.wiFi; }, // if true sort top
        megapixel: function (o) { return parseFloat(o.megapixel) || 0; },
    };

mapped.sort(function (a, b) {
    var r = 0;
    fields.some(function (c) {				
        return (r = types[c](a) - types[c](b));
    });
    return r;
});

document.write('<pre>' + JSON.stringify(mapped, 0, 4) + '</pre>');

Comments

0

Thanks to all your suggestions, I have tried to combine them all and come up with this:

// Sort our mapped array
mapped.sort(function (a, b) {

    // Loop through our properties
    for (var i = 0; i < fields.length; i++) {

        // Get our field
        var field = fields[i];

        // Get our value (skip the first)
        var x = a[field.name];
        var y = b[field.name];

        // If our values are the same, go to the next compare
        if (x === y)
            continue;

        // Switch on the type
        switch (field.type) {

            // Boolean
            case "boolean":

                // Return our value
                return x ? -1 : 1;

            // Integer
            case "float":

                // Update our values
                x = parseFloat(x);
                y = parseFloat(y);

                // Return our value
                return x < y ? -1 : 1;

            // Default (string)
            default:

                // Return our value
                return x.localeCompare(y);
        }
    }

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.