Converting consecutive "numbers" to ranges
I would like some feedback on an algorithm that identifies ranges in a list of "numbers". Any feedback will be appreciated.
I have a series of strings indicating section numbers like this:
102.2, 102.3, 102.4, 102.5, 102.6, 102.16, 102.17, 102.18, 102.19
What I want to do is collapse three or more consecutive numbers into ranges:
102.2-102.6, 102.16-102.19
First, I convert the string to an array of sections numbers. Next, I get two lists of numbers; one with the hundreds, the other with the tens. Then, I go through these lists, identifying ranges and return a list of positions in the array. So, in this example, I get:
1
5
6
9
If the length of positions is less than the array, I know there is at least one range. Now I go through the ranges to figure out which members to eliminate from the array. I do this by starting at the end of the positions list and subtract
9 - 6 = 3
6 - 5 = 1
5 - 1 = 4
Any result > 1 is a range. I subtract 1 from the result and that tells me how many members to eliminate from the array. So for the first one, I delete two members after the 6, which are 7 and 8. I skip the second one because the result is not greater than 1. The third one gives me 4 - 1, so I delete 3 members after position 1 (2, 3, 4). The array is left with 102.2, 102.6, 102.16, 102.19.
Note that the way I get the hyphens in the correct position is not important here. Also, my descriptions of positions above assume 1 as the first position, not 0 as they are in JavaScript arrays.
Below is my code in JavaScript. Any suggestions for simplifying the algorithm are appreciated. Thanks.
Rick Quatro
var refs = "102.2, 102.3, 102.4, 102.5, 102.6, 102.16, 102.17, 102.18, 102.19";
// Convert the string into an array.
var refsArray = refs.split(", ");
// Split the numbers into hundreds and tens places.
var numbers = getNumberSets (refsArray);
// Return a list of positions in the array, indicating ranges.
var positions = getRangePositions (numbers);
// Delete the unneeded members from the refsArray.
removeRedundantMembers (positions, refsArray); alert (refsArray);
function removeRedundantMembers (positions, refsArray) {
var count = positions.length - 1, span = 0;
// Loop from the end of the array to the beginning
for (var i = count; i > 0; i -= 1) {
// Get the distance between to consecutive positions.
span = positions - positions[i-1];
if (span > 1) {
// Remove the unneeded members.
refsArray.splice(positions[i-1] + 1, span - 1);
}
}
}
function getRangePositions (numbers) {
// Make an array of positions.
var positions = [];
// Make variables to store the current hundreds and tens values.
var hundred = -99, ten = -99;
for (var i = 0, count = numbers.hundreds.length; i < count; i += 1) {
if (numbers.hundreds !== hundred) {
// hundreds value changed; store this position.
positions.push (i);
// Update current hundreds and tens values.
hundred = numbers.hundreds;
ten = numbers.tens;
} else {
// hundreds stayed the same; check tens place.
if (numbers.tens !== (ten + 1)) {
// More than one tens places skipped; store this position and the previous.
positions.push (i-1);
positions.push (i);
}
ten = numbers.tens;
}
}
// The last position is always needed.
positions.push (count-1);
return positions;
}
function getNumberSets (refsArray) {
// Make an object of arrays for the number parts.
var numbers = {hundreds: [], tens: []};
// Make a regular expression to split each number.
var regex = /^(\d+)\.(\d+)$/, match;
// Loop through the references and split each one at the dot.
for (var i = 0, count = refsArray.length; i < count; i += 1) {
if (regex.test (refsArray)) {
match = regex.exec (refsArray);
// Convert the individual strings to integers and add them to the arrays.
numbers.hundreds.push (parseInt(match[1], 10));
numbers.tens.push (parseInt(match[2], 10));
} else {
// Regex doesn't match, so add zeros to the arrays.
numbers.hundreds.push (0);
numbers.tens.push (0);
}
}
return numbers;
}

