# Converting consecutive "numbers" to ranges

**frameexpert**Dec 4, 2012 7:16 AM

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 [x] - [x-1]. So

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[i] - 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[i] !== hundred) { // hundreds value changed; store this position. positions.push (i); // Update current hundreds and tens values. hundred = numbers.hundreds[i]; ten = numbers.tens[i]; } else { // hundreds stayed the same; check tens place. if (numbers.tens[i] !== (ten + 1)) { // More than one tens places skipped; store this position and the previous. positions.push (i-1); positions.push (i); } ten = numbers.tens[i]; } } // 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[i])) { match = regex.exec (refsArray[i]); // 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; }