Search code examples
javascriptalgorithmalphabetical

How to create custom alphabetical order in JavaScript?


I have a custom alphabetical order for a custom script I've written. It is defined in the following code, as well as my attempt at specifying an alphabetize algorithm, which isn't working.

const symbols = [
  { ascii: "i", unicode: "\u0470" },
  { ascii: "a", unicode: "\u0500" },
  { ascii: "u", unicode: "\u03f0" },

  { ascii: "e", unicode: "\u0410" },
  { ascii: "E", unicode: "\u0450" },
  { ascii: "U", unicode: "\u04a0" },

  { ascii: "I", unicode: "\u03d0" },
  { ascii: "o", unicode: "\u04e0" },
  { ascii: "A", unicode: "\u03b0" },

  { ascii: "O", unicode: "\u04c0" },
  { ascii: "o#", unicode: "\u0390" },
  { ascii: "u#", unicode: "\u0430" },

  { ascii: "e#", unicode: "\u0451" },
  { ascii: "i#", unicode: "\u03d1" },
  { ascii: "a#", unicode: "\u0501" },

  { ascii: "m", unicode: "\u0100" },
  { ascii: "n", unicode: "\u0140" },
  { ascii: "q", unicode: "\u0160" },
  { ascii: "g", unicode: "\u0130" },
  { ascii: "d", unicode: "\u0060" },
  { ascii: "b", unicode: "\u0040" },
  { ascii: "p", unicode: "\u0030" },
  { ascii: "t", unicode: "\u00d0" },
  { ascii: "k", unicode: "\u0050" },

  { ascii: "h", unicode: "\u0120" },
  { ascii: "l", unicode: "\u0170" },
  { ascii: "w", unicode: "\u0110" },

  { ascii: "f", unicode: "\u00c0" },
  { ascii: "s", unicode: "\u0070" },
  { ascii: "C", unicode: "\u00b0" },

  { ascii: "z", unicode: "\u0090" },
  { ascii: "v", unicode: "\u00f0" },
  { ascii: "y", unicode: "\u0180" },

  { ascii: "x", unicode: "\u0190" },
  { ascii: "r", unicode: "\u00e0" },

  { ascii: "c", unicode: "\u0080" },
  { ascii: "j", unicode: "\u0150" },
  { ascii: "Q", unicode: "\u01a0" },

  { ascii: "S", unicode: "\u0072" },
  { ascii: "Z", unicode: "\u0092" },
  { ascii: "H", unicode: "\u0122" },

  { ascii: "'", unicode: "\u01b0" },
]

const alphabet = symbols.map(o => o.ascii)

const words = [
  'He',
  'Hix',
  'Hex',
  'SoHiz',
  'SoH',
  'xo',
  'SoHi',
  'Hi',
  'CU'
]

const alphabetize = (array, alphabet) => {
  return array.sort((a, b) => {
    for (let i = 0, n = a.length; i < n; i++) {
      let x = a[i]
      let y = b[i]
      if (y) {
        let diff = alphabet.indexOf(x) - alphabet.indexOf(y)
        if (diff) return diff
      } else {
        return -1
      }
    }
  })
}

console.log(alphabetize(words, alphabet).join('\n'))

The output should be:

CU
xo
SoH
SoHi
SoHiz
Hi
Hix
He
Hex

What am I doing wrong here, and how can this become optimal?


Solution

  • Two things:

    • if b[i] is undefined, then the return value should not be -1, but 1: this will put the shorter b before the longer a.

    • There is a possibility that the for loop will complete without a return exit. In that case it could be that a and b are equal or b is longer. You need to return a good value for that case.

    Here is a correction:

    const symbols = [{ ascii: "i", unicode: "\u0470" },{ ascii: "a", unicode: "\u0500" },{ ascii: "u", unicode: "\u03f0" },{ ascii: "e", unicode: "\u0410" },{ ascii: "E", unicode: "\u0450" },{ ascii: "U", unicode: "\u04a0" },{ ascii: "I", unicode: "\u03d0" },{ ascii: "o", unicode: "\u04e0" },{ ascii: "A", unicode: "\u03b0" },{ ascii: "O", unicode: "\u04c0" },{ ascii: "o#", unicode: "\u0390" },{ ascii: "u#", unicode: "\u0430" },{ ascii: "e#", unicode: "\u0451" },{ ascii: "i#", unicode: "\u03d1" },{ ascii: "a#", unicode: "\u0501" },{ ascii: "m", unicode: "\u0100" },{ ascii: "n", unicode: "\u0140" },{ ascii: "q", unicode: "\u0160" },{ ascii: "g", unicode: "\u0130" },{ ascii: "d", unicode: "\u0060" },{ ascii: "b", unicode: "\u0040" },{ ascii: "p", unicode: "\u0030" },{ ascii: "t", unicode: "\u00d0" },{ ascii: "k", unicode: "\u0050" },{ ascii: "h", unicode: "\u0120" },{ ascii: "l", unicode: "\u0170" },{ ascii: "w", unicode: "\u0110" },{ ascii: "f", unicode: "\u00c0" },{ ascii: "s", unicode: "\u0070" },{ ascii: "C", unicode: "\u00b0" },{ ascii: "z", unicode: "\u0090" },{ ascii: "v", unicode: "\u00f0" },{ ascii: "y", unicode: "\u0180" },{ ascii: "x", unicode: "\u0190" },{ ascii: "r", unicode: "\u00e0" },{ ascii: "c", unicode: "\u0080" },{ ascii: "j", unicode: "\u0150" },{ ascii: "Q", unicode: "\u01a0" },{ ascii: "S", unicode: "\u0072" },{ ascii: "Z", unicode: "\u0092" },{ ascii: "H", unicode: "\u0122" },{ ascii: "'", unicode: "\u01b0" },];
    
    const alphabet = symbols.map(o => o.ascii);
    
    const words = ['He','Hix','Hex','SoHiz','SoH','xo','SoHi','Hi','CU']
    
    const alphabetize = (array, alphabet) => {
      return array.sort((a, b) => {
        for (let i = 0, n = a.length; i < n; i++) {
          let x = a[i];
          let y = b[i];
          if (y) {
            let diff = alphabet.indexOf(x) - alphabet.indexOf(y);
            if (diff) return diff;
          } else {
            return 1; // <-- corrected
          }
        }
        return a.length - b.length; // is 0 or negative
      })
    }
    
    console.log(alphabetize(words, alphabet).join('\n'));