Human Sort

Sorts elements in a way that follows english conventions

by sperske

HTML

<table id='List'>
  <tr>
    <td>Now That's What I Call Music 1</td>
  </tr>
  <tr>
    <td>now That's What I Call Music 11</td>
  </tr>
  <tr>
    <td>August And Everything After</td>
  </tr>
  <tr>
    <td>Now That's What I Call Music 5</td>
  </tr>
  <tr>
    <td>The 1975</td>
  </tr>
  <tr>
    <td>They're 10,000 Strong</td>
  </tr>
</table>

JavaScript

const list = document.getElementById('List');
let items = Array.from(list.getElementsByTagName('td')).map(e => e.innerText);

console.log(items);
function normalize(item) {
	let name = item.toUpperCase().replace('THE ', '');
  let trailingNumberData = /.*\D(\d+)$/.exec(name);
  let trailingNumber;
  if (trailingNumberData) {
  	name = name.substring(0, name.length-trailingNumberData[1].length);
    trailingNumber = parseInt(trailingNumberData[1], 10);
  }
  return { name, trailingNumber };
}

function humanSort(items) {
  let sortedItems = items;
  //return items sorted by skipping "The" and ordering trailing
  //numbers numerically.
  sortedItems.sort((a, b) => {
  	let A = normalize(a);
    let B = normalize(b);
    
    if (A.name === B.name) {
    	if (A.trailingNumber && B.trailingNumber) {
      	return A.trailingNumber - B.trailingNumber;
      } else if(!A.trailingNumber && B.trailingNumber) {
      	return -1;
      } else if(A.trailingNumber && !B.trailingNumber) {
      	return 1;
      } else {
      	return 0;
      }
    } else {
    	return A.name.localeCompare(B.name);
    }
  });
  return sortedItems;
}

console.log(humanSort(items));
//render results
list.innerHTML = '';
humanSort(items).forEach((v, i) => {
  let row = document.createElement('tr');
  row.innerHTML = `<th>${i + 1}</th><td>${v}<td>`;
  list.append(row);
});