2

I need to sort an alphaNumeric list. I am able to sort but some how because it is alphaNumeric, I am not able to put the abc1 before the abc10.

My HTML Code:

<ul class="theList">
   <li><b>abc11:</b>Hello</li>
   <li><b>abc10:</b>Hello</li>
   <li><b>xyz24:</b>Hello</li>
   <li><b>abc1:</b>Hello</li>
   <li><b>xyz2:</b>Hello</li>
</ul>

My JavaScript:

  $(document).ready(function() {
    var list, i, switching, b, shouldSwitch;
    list = document.getElementsByClassName("theList");
    for (var j = 0; j < list.length; j++) {
      switching = true;
      while (switching) {
        switching = false;
        b = list[j].getElementsByTagName("li");
        for (i = 0; i < (b.length - 1); i++) {
          shouldSwitch = false;
          if (b[i].innerHTML.toLowerCase() > b[i + 1].innerHTML.toLowerCase()) {
            shouldSwitch = true;
            break;
          }
        }
        if (shouldSwitch) {
          b[i].parentNode.insertBefore(b[i + 1], b[i]);
          switching = true;
        }
      }
    }
  });

My Result:

  • abc10:Hello
  • abc11:Hello
  • abc1:Hello
  • xyz24:Hello
  • xyz2:Hello

Expected Result:

  • abc1:Hello
  • abc10:Hello
  • abc11:Hello
  • xyz2:Hello
  • xyz24:Hello

What am I missing?

1 Answer 1

1

It would probably be a lot easier to sort the lis in their own array, outside of the document, and then append them to the ul again in the correct order. You can use localeCompare to check which string comes first lexicographically, no jQuery required:

const theList = document.querySelector('.theList');
const lis = Array.from(theList.children);
const firstText = elm => elm.children[0].textContent;
lis.sort((a, b) => firstText(a).localeCompare(firstText(b)));
lis.forEach(li => theList.appendChild(li));
<ul class="theList">
   <li><b>abc11:</b>Hello</li>
   <li><b>abc10:</b>Hello</li>
   <li><b>xyz24:</b>Hello</li>
   <li><b>abc1:</b>Hello</li>
   <li><b>xyz2:</b>Hello</li>
</ul>

To sort multiple such lists, iterate over a querySelectorAll:

document.querySelectorAll('.theList').forEach((theList) => {
  const lis = Array.from(theList.children);
  const firstText = elm => elm.children[0].textContent;
  lis.sort((a, b) => firstText(a).localeCompare(firstText(b)));
  lis.forEach(li => theList.appendChild(li));
});
<ul class="theList">
   <li><b>abc11:</b>Hello</li>
   <li><b>abc10:</b>Hello</li>
   <li><b>xyz24:</b>Hello</li>
   <li><b>abc1:</b>Hello</li>
   <li><b>xyz2:</b>Hello</li>
</ul>

<ul class="theList">
   <li><b>abc11:</b>Hello</li>
   <li><b>abc10:</b>Hello</li>
   <li><b>xyz24:</b>Hello</li>
   <li><b>abc1:</b>Hello</li>
   <li><b>xyz2:</b>Hello</li>
</ul>

Sign up to request clarification or add additional context in comments.

10 Comments

this works great but, I have multiple such lists with the same class name. This one only sorts the first list.
See edit, use querySelectorAll instead and iterate
This works like a charm! Thank you! I am trying to use the logic above for just one select element. I seem to be getting an error. I would've thought the logic behind it is the same.
I just noticed a sorting issue and was hoping you can help me with it. When I run your code, I do get the values sorted. But incase I add a abc2 to the list. It sorts it like this: abc1, abc10, abc11, abc2. Is there any ways for me to get it like abc1, abc2, abc10, abc11
Pass another argument to localeCompare: 'en-u-kn-true' and it will compare the numbers as numbers rather than lexiographically.
|

Your Answer

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