Jaakko Pöntinen
Jaakko Pöntinen

Reputation: 13

Sort an array in a certain way

I've an array which is being populated by options in select dropdowns.

jQuery('.wcpf-input-drop-down').each(function () {
var sel = jQuery(this);
var selected = sel.val(); // cache selected value, before reordering
var opts_list = sel.find('option');
opts_list.sort(function(a, b) { return jQuery(a).text() > jQuery(b).text() ? 1 : -1; });
sel.html('').append(opts_list);
sel.val(selected); // set cached selected value
    });

The above code is from Sorting options elements alphabetically using jQuery, written by Malak George. EDIT: I've modified it to look for all instances separately.

Now, this is working fine as far as finding the instances of .wcpf-input-drop-down and sorting the options within.

However, this sorting produces ordering in this fashion: "1, 2, 26, 27, 28, 3, 31" and so on.

I would need it to sort as follows: "1, 2, 3, 26, 27, 28, 31".

I've been searching for hours and found plenty of talk on the subject, but I cannot get to where I want. I'm sure I've seen ways to accomplish what I need, but haven't been able to. I think here's one that I could use, if I'd only know how to insert that into my existing code: Sort Array Elements (string with numbers), natural sort

Could someone help me implement the sorting I wish to see into the code I have now?

Thank you.

EDIT2: Here's a pen with all the relevant data to this question: https://codepen.io/jpontinen/pen/NJrXKQ

Upvotes: 1

Views: 70

Answers (3)

zer00ne
zer00ne

Reputation: 43880

Details are commented in demo.

/* 
On each select.sel...
...get all of its options...
...then make an array of those option.
Next, sort the array of options by their .value...
...and remove everything in select.sel...
...and append the sorted array in select.sel
*/
$('.sel').each(function(i) {
  var opt = $(this).find('option');
  var arr = $.makeArray(opt);
  var sorted = arr.sort(function(a, b) {
    return parseInt(a.value, 10) - parseInt(b.value, 10);
  });
  $(this).empty().append(sorted);
});
<select class="sel">
  <option value="0">0</option>
  <option value="1">1</option>
  <option value="10">10</option>
  <option value="107">107</option>
  <option value="108">108</option>
  <option value="11">11</option>
  <option value="75">75</option>
  <option value="8">8</option>
  <option value="83">83</option>
  <option value="9">9</option>
  <option value="110">110</option>
  <option value="111">111</option>
  <option value="114">114</option>
  <option value="12">12</option>
  <option value="71">71</option>
  <option selected>Values to be sorted</option>
</select>

<hr>

<select class="sel">
  <option value="11">11</option>
  <option value="89">89</option>
  <option value="5">5</option>
  <option value="0">0</option>
  <option value="46">46</option>
  <option value="33">33</option>
  <option value="1">1</option>
  <option value="6">6</option>
  <option value="21">21</option>
  <option value="40">40</option>
  <option value="24">24</option>
  <option value="175">175</option>
  <option value="81">81</option>
  <option value="123">123</option>
  <option value="94">94</option>
  <option selected>Values to be sorted</option>
</select>

<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

Upvotes: 0

Leftium
Leftium

Reputation: 17903

The problem is you are sorting strings lexicographically ("26" comes before "3").

You want to sort by numeric value (by converting the strings to numbers):

// Implicitly cast to Number type using subtraction operator.
opts_list.sort(function(a, b) {
    return jQuery(a).text() - jQuery(b).text();
});

Here are some other variations:

// Fewest changes to original version in question.
// Explicit conversion using parseInt().
opts_list.sort(function(a, b) {
    // Should return 0 when a and b are equal, but this version returns -1.
    return parseInt(jQuery(a).text()) > parseInt(jQuery(b).text()) ? 1 : -1;
});
// Explicitly convert to integer type using parseInt.
// Note `jQuery(a).text()` can be simplified to `a.text`
opts_list.sort(function(a, b) {
    return parseInt(a.text, 10) - parseInt(b.text, 10);
});

Upvotes: 0

trincot
trincot

Reputation: 350272

Subtract the options in your sorting callback, that way they are automatically coerced to number data type:

opts_list.sort(function(a, b) { 
     return jQuery(a).text() - jQuery(b).text()
});

If you also have drop-down lists that contain non-numerical data, that need alphabetical sorting, then you need a natural sort method:

opts_list.sort(function(a, b) { 
  return jQuery(a).text().localeCompare(jQuery(b).text(), undefined, {numeric: true, sensitivity: 'base'});
});

Upvotes: 1

Related Questions