Java: Convert int[] to smallest representation as ranges
Given an array of int values, how could one parse the series into counting sequence notation?
Examples:
{1, 2, 3, 4, 5, 9, 13, 14, 15} -> "1-5,9,13-15"
{4, 6, 8, 10, 11, 12, 15, 17} -> "4,6,8,10-12,15,17"
I'm looking for a method that would produce these results. This is what I have so far, but I'm very much stumped at this point:
Test Code:
import java.util.Arrays;
public class TestSequencing {
public static void main(String[] args) {
int[] numbers1 = {1, 2, 3, 4, 5, 9, 13, 14, 15};
String numbers1s = "1-5,9,13-15";
System.out.println(Arrays.toString(numbers1));
System.out.println("Expected:t" + numbers1s);
System.out.println("Produced:t" + sequenceNums(numbers1) + "n");
int[] numbers2 = {3, 5, 6, 9, 12};
String numbers2s = "3,5-6,9,12";
System.out.println(Arrays.toString(numbers2));
System.out.println("Expected:t" + numbers2s);
System.out.println("Produced:t" + sequenceNums(numbers2) + "n");
int[] numbers3 = {1, 2, 3, 4, 5, 6, 7};
String numbers3s = "1-7";
System.out.println(Arrays.toString(numbers3));
System.out.println("Expected:t" + numbers3s);
System.out.println("Produced:t" + sequenceNums(numbers3) + "n");
}
public static String sequenceNums(int[] nums) {
StringBuilder sb = new StringBuilder();
int rangeStart = nums[0];
int previous = nums[0];
int current;
int expected = previous + 1;
for (int i = 1 ; i < nums.length ; i++) {
current = nums[i];
expected = previous + 1;
if (current != expected || i == (nums.length - 1)) {
if (current == rangeStart) {
sb.append(previous + ",");
} else {
sb.append(rangeStart + "-" + previous + ",");
}
rangeStart = current;
}
previous = current;
}
if (sb.charAt(sb.length() - 1) == ',') {
sb.deleteCharAt(sb.length() - 1);
}
return sb.toString();
}
}
Output:
[1, 2, 3, 4, 5, 9, 13, 14, 15]
Expected: 1-5,9,13-15
Produced: 1-5,9-9,13-14
[3, 5, 6, 9, 12]
Expected: 3,5-6,9,12
Produced: 3-3,5-6,9-9
[1, 2, 3, 4, 5, 6, 7]
Expected: 1-7
Produced: 1-6
尝试这个:
private static void appendRange(StringBuilder sb, int begin, int end) {
sb.append(",").append(begin);
if (end != begin)
sb.append("-").append(end);
}
public static String sequenceNums(int[] nums) {
StringBuilder sb = new StringBuilder();
if (nums.length == 0) return sb.toString();
int begin = nums[0], end = nums[0];
for (int cur : nums)
if (cur - end <= 1)
end = cur;
else {
appendRange(sb, begin, end);
begin = end = cur;
}
appendRange(sb, begin, end);
return sb.substring(1);
}
@Test
public void testSequenceNums() {
assertEquals("1-5,9,13-15", sequenceNums(new int[] {1, 2, 3, 4, 5, 9, 13, 14, 15}));
assertEquals("4,6,8,10-12,15,17", sequenceNums(new int[] {4, 6, 8, 10, 11, 12, 15, 17}));
assertEquals("1-7", sequenceNums(new int[] {1, 2, 3, 4, 5, 6, 7}));
assertEquals("", sequenceNums(new int[] {}));
}
In the for loop you have two issues:
1) The second if
should be if (previous == rangeStart) {
2) You're not dealing with the last number in the loop (where i == (nums.length - 1)
).
I would do this with the following code:
public static String sequenceNums(int[] nums) {
StringBuilder sb = new StringBuilder();
int rangeStart = nums[0];
int previous = nums[0];
int current;
int expected = previous + 1;
int size = nums.length;
for (int i = 1 ; i < size ; i++) {
current = nums[i];
expected = previous + 1;
if (current != expected) {
addRange(sb, rangeStart, previous);
rangeStart = current;
}
previous = current;
}
addRange(sb, rangeStart, nums[size - 1]);
return sb.toString();
}
private void addRange(StringBuilder sb, int from, int to) {
if (sb.length() > 0) {
sb.append(",");
}
if (from == to) {
sb.append(from);
} else {
sb.append(from + "-" + to);
}
}
Here is your fixed code.
public class TestSequencing {
public static void main(String[] args) {
int[] numbers1 = {1, 2, 3, 4, 5, 9, 13, 14, 15};
String numbers1s = "1-5,9,13-15";
System.out.println(Arrays.toString(numbers1));
System.out.println("Expected:t" + numbers1s);
System.out.println("Produced:t" + sequenceNums(numbers1) + "n");
int[] numbers2 = {3, 5, 6, 9, 12};
String numbers2s = "3,5-6,9,12";
System.out.println(Arrays.toString(numbers2));
System.out.println("Expected:t" + numbers2s);
System.out.println("Produced:t" + sequenceNums(numbers2) + "n");
int[] numbers3 = {1, 2, 3, 4, 5, 6, 7};
String numbers3s = "1-7";
System.out.println(Arrays.toString(numbers3));
System.out.println("Expected:t" + numbers3s);
System.out.println("Produced:t" + sequenceNums(numbers3) + "n");
}
public static String sequenceNums(int[] nums) {
StringBuilder sb = new StringBuilder();
int rangeStart = nums[0];
int previous = nums[0];
int current;
int expected = previous + 1;
for (int i = 1 ; i < nums.length ; i++) {
current = nums[i];
expected = previous + 1;
if (current != expected || i == (nums.length - 1)) {
if (current == rangeStart) {
sb.append(previous + ",");
} else {
if(rangeStart != previous) {
if(i == nums.length - 1)
sb.append(rangeStart + "-" + current);
else
sb.append(rangeStart + "-" + previous + ",");
} else {
if(i == nums.length - 1)
sb.append(rangeStart + "," + current);
else
sb.append(rangeStart + ",");
}
}
rangeStart = current;
}
previous = current;
}
if (sb.charAt(sb.length() - 1) == ',') {
sb.deleteCharAt(sb.length() - 1);
}
return sb.toString();
}
}
Problem was, if current is not same as range starting value, you need to check for two cases
i) if range was starting with the same previous value. If so, no need to have same number separated by range (ex: 9-9 doesn't make sense. only 9 does). Another case to be handled is end of array reached. In case end of array is reached, it should just be added at the end even thought it does not fall in any range
ii) other wise, range starts and ends with previous value if end of array is not reached. If end of array is reached that would be end value of range
链接地址: http://www.djcxy.com/p/86428.html