4

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);

8
  • “I am doing a base sort of the first letters, and if that doesn't work […]” – that seems to make little sense to me; why not use your “real” sort function to begin with? If that can decide based on the first letter already, then this should be as close as makes no difference performance-wise to your more complicated and more convoluted approach … Commented Feb 25, 2015 at 5:20
  • Looks like you just need to swap return 1; with return -1; inside deep sort. Commented Feb 25, 2015 at 5:22
  • already tried swap return Commented Feb 25, 2015 at 5:49
  • Like this? jsfiddle.net/wLmgyc83 Commented Feb 25, 2015 at 5:56
  • still not doing it look at apple and abbot Commented Feb 25, 2015 at 6:27

2 Answers 2

4

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.

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

2 Comments

I tried this with given data as Array of alphabets: ['h','g','k','r','o','e','a','j','c','n','b'] Array of names: ['jack','rob','josh','john','greg’] Use “alphabets” array to sort the names array. expected result == [greg, rob, john, josh, jack] but result is [greg,jack,john,josh,rob] codepen.io/mayankbhadauria/pen/qBjjzWO
@Mayank: for this code to work, sortingString must be a permutation of the alphabet, that is, contain all 26 letters.
4

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));

Comments

Your Answer

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

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.