JohnJohnGa
JohnJohnGa

Reputation: 15685

Sort select list by count and value

I have an html list

<select>
  <option value="w" count="1">w (1)</option>
  <option value="a" count="1">a (1)</option>
  <option value="d" count="5">d (5)</option>
  <option value="r" count="0">r (0)</option>
  <option value="q" count="0">q (0)</option>
  <option value="s" count="0">s (0)</option>
  <option value="b" count="5">b (5)</option>
</select>

I want the list to be order by count first, then by value.

Output:

<select>  
  <option value="b" count="5">b (5)</option>
  <option value="d" count="5">d (5)</option>
  <option value="a" count="1">a (1)</option>
  <option value="w" count="1">w (1)</option>
  <option value="q" count="0">q (0)</option>
  <option value="r" count="0">r (0)</option>
  <option value="s" count="0">s (0)</option>
</select>

I know how to sort by count OR by value but I don't find an easy way to combine them.

Sort by count:

select.sort(function (a, b) {
    var c1 = parseInt($(a).attr('count'), 10);
    var c2 = parseInt($(b).attr('count'), 10);
    return c1 < c2 ? 1 : c1 > c2 ? -1 : 0;
});

and by value

select.sort(function (a, b) {
    return $(a).text().toUpperCase().localeCompare($(b).text());
});

I am thinking about building an object:

var map = {
    5: ['d', 'b'],
    1: ['a', 'w'],
    0: ['r', 'q', 's']
};

Then sort each keys:

function keys(map) {
    var keys = [];
    for (var key in map) {
        if (map.hasOwnProperty(key)) map[key].sort();
    }
    return keys;
}

keys(map);
map;

And finally reconstruct the select list.

Is there an easier way?

Upvotes: 0

Views: 163

Answers (2)

Cerbrus
Cerbrus

Reputation: 72957

Try this:

select.sort(function (a, b) {
    var c1 = parseInt($(a).attr('count'), 10);
    var c2 = parseInt($(b).attr('count'), 10);

    if(c1 === c2){ // If the counts are equal, return the comparison for value.
        return $(a).text().toUpperCase().localeCompare($(b).text());
    }
    // Otherwise, compare the counts.
    // (With numbers, you can just substract `b` from `a` in sort functions.)
    return c1 - c2;
});

With the comments removed, that's just 6 lines of code.

There's no need to wrap the second return in a else, because the sort function won't ever evaluate an else, if c1 === c2, since the if contains a return statement.

Now, the sort function expects X<0, X=0 or X>0 to be returned (Where X is the output), depending on if a is less than, equal to, or greater than b. If you subtract b from a, you get the values you need.

Upvotes: 1

Sirko
Sirko

Reputation: 74086

Why not just combine both functions into one like this:

select.sort(function (a, b) {
    var c1 = parseInt($(a).attr('count'), 10);
    var c2 = parseInt($(b).attr('count'), 10);

    if ( c1 == c2 ) {
      return $(a).text().toUpperCase().localeCompare($(b).text());
    } else {
      return c1 < c2 ? 1 : -1;
    }
});

Upvotes: 1

Related Questions