case sensitive sorting in javascript, where all capital letters come before all lowercase letters

Viewed 382

I need to sort two strings in a way that capital letters come first, even for different letters, for example:

Cat comes before ant

CD comes before Cd

Can I use localCompare to sort like that?

const sortString = (a, b) => String(a).localeCompare(b);
4 Answers

No, you can't (and don't need to) use localeCompare for that. What you describe is just the standard string comparison, which puts letters in alphabetical order and uppercase letters before the lowercase ones!

So all you need to do is

arr.sort((a, b) => +(a>b)||-(b>a))

which for strings is the same as the default fallback comparison function so you can just do

arr.sort()

My function return 1 if first string is greater, -1 if first string is less than and 0 if it is equal second string.

// return value like compare function
const findCompareValue = (flag) => {
  if (flag) {
    return -1;
  } else {
    return 1;
  }
}

const compareCaseSensitive = (a, b) => {
  // find min length just in case two string don't have the same length
  const minLen = a.length > b.length ? b.length : a.length;
  let i = 0;

  const minLowerCaseCharCode = 97;
  const maxLowerCaseCharCode = 122;
  const minUpperCaseCharCode = 65;
  const maxUpperCaseCharCode = 90;

  while (true && i !== minLen) {
    // get char code
    const aCharCode = a[i].charCodeAt();
    const bCharCode = b[i].charCodeAt();

    // check whether character is uppercase
    const isACharUpperCase = minUpperCaseCharCode <= aCharCode && aCharCode <= maxUpperCaseCharCode;
    const isBCharUpperCase = minUpperCaseCharCode <= bCharCode && bCharCode <= maxUpperCaseCharCode;

    if (isACharUpperCase) {
      if (isBCharUpperCase  && bCharCode !== aCharCode) {
        // two characters are uppercase and different
        return findCompareValue(aCharCode < bCharCode);
      } else if (aCharCode !== bCharCode) {
        // second character is lowercase
        return 1;
      }
    } else {
      if (isBCharUpperCase) {
        // second string is uppercase
        return -1;
      } else if (aCharCode !== bCharCode) {
        // two characters are lowercase and different
        return findCompareValue(aCharCode < bCharCode);
      }
    }

    i += 1;
  }

  return 0;
}

const a = 'CD';
const b = 'cD';

console.log('result', compareCaseSensitive(a, b));

Can you try this, not sure all the requirements are satisfied or not...

Input: ['Cat', 'March', 'aJan','Feb', 'Feb', 'Dd', 'DD', 'ant', 'cat', 'AMC', 'AMBulance', 'Feb','Cd' , 'CD']

Output: ["AMBulance", "AMC", "CD", "Cat", "Cd", "DD", "Dd", "Feb", "Feb", "Feb", "March", "aJan", "ant", "cat"]

const months = ['Cat', 'March', 'aJan','Feb', 'Feb', 'Dd', 'DD', 'ant', 'cat', 'AMC', 'AMBulance', 'Feb','Cd' , 'CD']

function _sort(a,b) {
  
  const aLenth = a.length
  const bLenth = b.length
  
  const aArr = a.match(/^[A-Z]*/g )
  const bArr = b.match(/^[A-Z]*/g )
  const isCapA = Array.isArray(aArr) && !!aArr[0].length
  const isCapB = Array.isArray(bArr) && !!bArr[0].length
  
  const isBothCapital = isCapA && isCapB // then check usual way
  const isBothSimple = !isCapA && !isCapB // then check usual way
  
  //console.log(a, b, isBothCapital, aArr.length, bArr.length)
  if (isBothCapital || isBothSimple){
    if (a === b )  {
      return 0 
    }
    if (aArr[0].length ===  bArr[0].length) {
        return a.localeCompare(b);
    }
   //return a.localeCompare(b);
    return  aArr[0].length - bArr[0].length ? 1 : -1
  }
  if (isCapA) {
    return -1
  }
  
  return 1
  
}
const _simpSort = (a,b ) => {
    return a.localeCompare(b)
}
const capLetters = months.filter(x => x.match(/^[A-Z]/g))
const simpLetters = months.filter(x => x.match(/^[a-z]/g))
const formatted = [...capLetters.sort(_simpSort), ...simpLetters.sort(_simpSort)]

const groupBy = formatted.reduce((acc, i) => {
  
    const isExists = acc[i.charAt(0)]
    const ele = typeof isExists !== "undefined" ? isExists : []
   
    const tmp = { [i.charAt(0)]: [i, ...ele] }

    return { ...acc, ...tmp}
}, {})
const final = []
for (ele in groupBy) {
    const tmpRow = groupBy[ele].sort(_sort)
    final.push(tmpRow)
}

console.log(final.join().split(","))

You're lucky because A-Z char code is smaller than a-z, so we can just use charCode to sort.

The tricky bit is to loop through each character.

const list = ['Cat', 'Cat2', 'ant', 'CD', 'Cd', 'cD', 'Ab', 'zb', 'zC'];

const sortByCharcode = (a, b) => {
  if (a.charCodeAt(0) < b.charCodeAt(0)) return -1;
  if (a.charCodeAt(0) > b.charCodeAt(0)) return 1;
  return 0;
}

const sortFunc = (strA, strB) => {
  // Loop through each character.
  for (let i = 0; i < strB.length; i++) {
    const a = strA[i];
    const b = strB[i];
    const compareResult = sortByCharcode(a, b); // Compare each index

// If result is -1 or 1, return it, if it's still 0 then move to next character.
    if (compareResult !== 0) return compareResult;
  }
  // If strB.length run out, A comes before B
  return 1;
}

const sortedList = list.sort(sortFunc);
console.log(sortedList);

Related