MR.Dhillon
MR.Dhillon

Reputation: 41

sorting string function by custom alphabet javascript

Trying to sort an array of strings based on a custom alphabet. Probably some unnecessary code in there, but that was a couple different iterations mixed into one.

I am doing a base sort of the first letters, and if that doesn't work, I call the deep sort function and start working down the letters. But the result is only sorted by first letter, and the latter sorting seems to be arbitrary.

Any help?

var wordArray = ['apple', 'abbot', 'aatrophy', 'banana', 'berry', 'cherrypie', 'cherry', 'candy', 'grapefruit', 'pear', 'pizza', 'zebra', 'cigarette', 'guitar'];
var wordToLetterArray = [];
// var sortingString = "kwfhjrsbdtqmxaopzvieulgcny";
var sortingString = "abcdefghijklmnopqrstuvwxyz";

var deepSort = function(wordArray1, wordArray2) {
var forLoopIterations = 0;
if (wordArray1 && wordArray2) {
    if (wordArray1.length > wordArray2.length) {
        forLoopIterations = wordArray2.length;
    } else {
        forLoopIterations = wordArray1.length;
    }

    for (var i = 0; i <= forLoopIterations; i++) {
        if (sortingString.indexOf(wordArray1[i]) > sortingString.indexOf(wordArray2[i])) {
            return -1;
        } else if (sortingString.indexOf(wordArray1[i]) < sortingString.indexOf(wordArray2[i])) {
            return 1
        } else {
            if (i >= forLoopIterations) {
                if (wordArray1.length > wordArray2.length) {
                    return 1;
                } else if (wordArray1.length < wordArray2.length) {
                    return -1
                } else {
                    return 0
                }
            } else {

            }

        }
    };
} else {
    return 0;
}

}

var populateWordToLetterArray = function() {
for (var i = 0; i <= wordArray.length - 1; i++) {
    wordToLetterArray.push([]);
    for (var x = 0; x <= wordArray[i].length - 1; x++) {

        wordToLetterArray[i].push(wordArray[i][x]);
    };
};
sortWordArraybyFirstLetter();
}



var sortWordArraybyFirstLetter = function sortWordArraybyFirstLetter() {
wordArray.sort(function(a, b) {
    var aIndex = sortingString.indexOf(a[0]);
    var bIndex = sortingString.indexOf(b[0]);
    if (aIndex > bIndex) {
        return 1;
    } else if (aIndex < bIndex) {
        return -1;
    } else {

        return deepSort(wordToLetterArray[wordArray.indexOf(a)], wordToLetterArray[wordArray.indexOf(b)]);


    }
})

}




populateWordToLetterArray();
console.log(wordArray);
console.log(wordToLetterArray);

Upvotes: 4

Views: 2041

Answers (2)

JLRishe
JLRishe

Reputation: 101662

It's very difficult to reason about code when you're nesting that deep. What you need is a clean way of producing a function to compare two strings based on your sort order. Once you have that, everything gets simpler.

The following should work for that:

function makeComparer(order) {
  var ap = Array.prototype;

  // mapping from character -> precedence
  var orderMap = {},
      max = order.length + 2;
  ap.forEach.call(order, function(char, idx) {
    orderMap[char] = idx + 1;
  });

  function compareChars(l, r) {
    var lOrder = orderMap[l] || max,
        rOrder = orderMap[r] || max;

    return lOrder - rOrder;
  }

  function compareStrings(l, r) {
    var minLength = Math.min(l.length, r.length);
    var result = ap.reduce.call(l.substring(0, minLength), function (prev, _, i) {
        return prev || compareChars(l[i], r[i]);
    }, 0);

    return result || (l.length - r.length);
  }

  return compareStrings;
}

var comparer = makeComparer('abcdefghijklmnopqrstuvwxyz');
console.log(comparer('apple', 'abbot'));
console.log(comparer('abbot', 'apple'));
console.log(comparer('apple', 'apple'));
console.log(comparer('apple', 'apple pie'));
console.log(comparer('apple pie', 'apple'));

Once you have that, sorting is as simple as using the built-in sort method:

var comparer = makeComparer('abcdefghijklmnopqrstuvwxyz');
var wordArray = ['apple', 'abbot', 'aatrophy', 'banana', 
                 'berry',  'cherrypie','cherry', 'candy', 
                 'grapefruit', 'pear', 'pizza', 'zebra', 
                 'cigarette', 'guitar'];
wordArray.sort(comparer);

Full solution:

function makeComparer(order) {
  var ap = Array.prototype;

  // mapping from character -> precedence
  var orderMap = {},
      max = order.length + 2;
  ap.forEach.call(order, function(char, idx) {
    orderMap[char] = idx + 1;
  });

  function compareChars(l, r) {
    var lOrder = orderMap[l] || max,
        rOrder = orderMap[r] || max;

    return lOrder - rOrder;
  }

  function compareStrings(l, r) {
    var minLength = Math.min(l.length, r.length);
    var result = ap.reduce.call(l.substring(0, minLength), function (prev, _, i) {
        return prev || compareChars(l[i], r[i]);
    }, 0);

    return result || (l.length - r.length);
  }

  return compareStrings;
}

var wordArray = ['apple', 'abbot', 'aatrophy', 'banana', 
                 'berry',  'cherrypie','cherry', 'candy', 
                 'grapefruit', 'pear', 'pizza', 'zebra', 
                 'cigarette', 'guitar'];
var comparer = makeComparer('abcdefghijklmnopqrstuvwxyz');
console.log(wordArray.slice().sort(comparer));

var weirdComparer = makeComparer("kwfhjrsbdtqmxaopzvieulgcny");
console.log(wordArray.slice().sort(weirdComparer));

Upvotes: 3

georg
georg

Reputation: 214949

Make a function that "translates" a word into your custom alphabet and then sort the words by comparing their "translations":

function translate(str, alphabet) {
    var abc = "abcdefghijklmnopqrstuvwxyz";
    return [].map.call(str, function(c) {
        return alphabet[abc.indexOf(c)] || c;
    }).join("");
}

var wordArray = ['apple', 'abbot', 'aatrophy', 'banana', 'berry', 'cherrypie', 'cherry', 'candy', 'grapefruit', 'pear', 'pizza', 'zebra', 'cigarette', 'guitar'];
var sortingString = "kwfhjrsbdtqmxaozpvieulgcny";

wordArray.sort(function(a, b) {
    return translate(a, sortingString).localeCompare(translate(b, sortingString));
});

document.write(wordArray)

This isn't particularly efficient, but there's room for optimizations.

Upvotes: 4

Related Questions