getRankBetween method
Generate a lexo rank between two rank.
the firstRank
should be lower than the secondRank
unless the reorderPosition is true
Implementation
// inspired by https://medium.com/whisperarts/lexorank-what-are-they-and-how-to-use-them-for-efficient-list-sorting-a48fc4e7849f
String getRankBetween(
{required String firstRank, required String secondRank}) {
final firstPositionIsLower = firstRank.compareTo(secondRank) < 0;
if (!firstPositionIsLower) {
if (reorderPosition) {
final f = firstRank;
firstRank = secondRank;
secondRank = f;
} else {
throw LexoRankException(
'First position must be lower than second. '
'Got firstRank $firstRank and second rank $secondRank',
);
}
}
/// Make positions equal
while (firstRank.length != secondRank.length) {
if (firstRank.length > secondRank.length) {
secondRank += "a";
} else {
firstRank += "a";
}
}
var firstPositionCodes = [];
firstPositionCodes.addAll(firstRank.codeUnits);
var secondPositionCodes = [];
secondPositionCodes.addAll(secondRank.codeUnits);
num difference = 0;
for (int index = firstPositionCodes.length - 1; index >= 0; index--) {
/// Codes of the elements of positions
var firstCode = firstPositionCodes[index];
var secondCode = secondPositionCodes[index];
/// i.e. ' a < b '
if (secondCode < firstCode) {
/// ALPHABET_SIZE = 26 for now
secondCode += alphabetSize;
secondPositionCodes[index - 1] -= 1;
}
/// formula: x = a * size^0 + b * size^1 + c * size^2
final powRes = pow(alphabetSize, firstRank.length - index - 1);
difference += (secondCode - firstCode) * powRes;
}
var newElement = "";
if (difference <= 1) {
/// add middle char from alphabet
newElement = firstRank +
String.fromCharCode('a'.codeUnits.first + alphabetSize ~/ 2);
} else {
difference ~/= 2;
var offset = 0;
for (int index = 0; index < firstRank.length; index++) {
/// formula: x = difference / (size^place - 1) % size;
/// i.e. difference = 110, size = 10, we want place 2 (middle),
/// then x = 100 / 10^(2 - 1) % 10 = 100 / 10 % 10 = 11 % 10 = 1
final diffInSymbols =
difference ~/ pow(alphabetSize, index) % (alphabetSize);
var newElementCode =
firstRank.codeUnitAt(secondRank.length - index - 1) +
diffInSymbols +
offset;
offset = 0;
/// if newElement is greater then 'z'
if (newElementCode > 'z'.codeUnits.first) {
offset++;
newElementCode -= alphabetSize;
}
newElement += String.fromCharCode(newElementCode);
}
newElement = newElement.split('').reversed.join();
}
return newElement;
}