说明
您可以简单地从左到右进行迭代并在此过程中保持范围。
为此,只需记住范围的开始和每次迭代中的最后一个值。然后,您可以轻松确定范围是刚刚停止还是继续。如果停止,结束该范围并开始下一个。
对于空数组的特殊情况,只需在方法的开头添加一个简单的if,单独处理即可。
构建范围
public static String buildRanges(int[] values) {
if (values.length == 0) {
return "";
}
StringJoiner result = new StringJoiner(", ");
int rangeStart = values[0];
int lastValue = values[0];
// Skip first value to simplify 'lastValue' logic
for (int i = 1; i < values.length; i++) {
int value = values[i];
if (value != lastValue + 1) {
// Range ended, wrap it up
int rangeEnd = lastValue;
result.add(rangeStart == rangeEnd
? Integer.toString(rangeStart)
: rangeStart + "~" + rangeEnd);
rangeStart = value;
}
lastValue = value;
}
// Conclude last range
int rangeEnd = lastValue;
result.add(rangeStart == rangeEnd
? Integer.toString(rangeStart)
: rangeStart + "~" + rangeEnd);
return result.toString();
}
简化
为了解决代码重复和提高可读性,我建议还引入一个辅助方法rangeToString:
public static String rangeToString(int rangeStart, int rangeEnd) {
return rangeStart == rangeEnd
? Integer.toString(rangeStart)
: rangeStart + "~" + rangeEnd);
}
然后代码简化为:
public static String buildRanges(int[] values) {
if (values.length == 0) {
return "";
}
StringJoiner result = new StringJoiner(", ");
int rangeStart = values[0];
int lastValue = values[0];
// Skip first value to simplify 'lastValue' logic
for (int i = 1; i < values.length; i++) {
int value = values[i];
if (value != lastValue + 1) {
// Range ended, wrap it up
result.add(rangeToString(rangeStart, lastValue);
rangeStart = value;
}
lastValue = value;
}
// Conclude last range
result.add(rangeToString(rangeStart, lastValue);
return result.toString();
}
面向对象的解决方案
如果您愿意,还可以引入专门的Range 类来解决这个问题。在这种特殊情况下可能有点矫枉过正,但仍然如此。
让我们首先创建一个知道其开始和结束的Range 类。此外,它可以正确地将自身转换为String,您可以尝试增加范围。
public final class Range {
private final int start;
private int end;
public Range(int value) {
start = value;
end = value;
}
public boolean add(int value) {
if (value != end + 1) {
return false;
}
end = value;
return true;
}
@Override
public String toString() {
return start == end
? Integer.toString(start)
: start + "~" + end;
}
}
现在您可以轻松地在一个简单的循环中使用它:
public static String buildRanges(int[] values) {
if (values.length == 0) {
return "";
}
StringJoiner result = new StringJoiner(", ");
Range range = new Range(values[0]);
// Skip first value to simplify logic
for (int i = 1; i < values.length; i++) {
int value = values[i];
if (!range.add(value)) {
// Range ended, wrap it up
result.add(range.toString());
range = new Range(value);
}
}
// Conclude last range
result.add(range.toString());
return result.toString();
}
收集到List<Range>
这种方法的优点是您还可以收集到List<Range> ranges 之类的东西,然后继续处理数据,而不仅仅是转到String。示例:
public static List<Range> buildRanges(int[] values) {
if (values.length == 0) {
return List.of();
}
List<Range> ranges = new ArrayList<>();
Range range = new Range(values[0]);
// Skip first value to simplify logic
for (int i = 1; i < values.length; i++) {
int value = values[i];
if (!range.add(value)) {
// Range ended, wrap it up
ranges.add(range);
range = new Range(value);
}
}
// Conclude last range
ranges.add(range);
return ranges;
}
如果您还向Range 类添加一些getStart() 和getEnd() 方法,则特别有用。
注意事项
请注意,如果数组包含重复项,则该方法可能会表现得很奇怪。您没有指定在这种情况下要做什么,所以我只是假设您的用例不存在重复项。