我正在编写一个C#程序,用户可以在其中以集合的形式输入一系列值,比如"1,2,4, 10-25,40+“,其中项可以是单个数字,范围可以是10-25,范围可以是无穷大,比如25+。范围必须至少是2个间隔,你不能说10-11,那应该是10,11。我需要函数来加减它们。
例如,"1,2,4,10-25,40+“+ "3,11,26”将返回"1-4,10-26,40+“
我在这里使用字符串作为示例,但假设数据已经解析为三个类别的对象:单个数字、范围和无限范围。我不是在问如何解析字符串。
我正在编写我自己的一组函数,并且看到由于范围必须相距2的事实,所以有很多复杂性。我知道有一些函数可以测试一个数字是否在一个范围内,这很容易构建到一个例程中来测试一个数字是否在一组范围内。
但是,我如何增加或减少集合,并简化它们,使您不得到11,12,13,而是11-13呢?这不是微不足道的。我对任何解决方案都是开放的,如果需要,我可以导入库。
发布于 2015-06-20 02:42:52
这是我写的一个小函数,用来帮助你……fiddle
代码段
private static List<string> Simplify(List<string> inputs)
{
var simpleList = new List<int>();
var retval = new List<string>();
bool infinity = false;
foreach (string input in inputs)
{
if (string.IsNullOrEmpty(input))
continue;
if (input.Split('-').Length > 1)
{
int min = int.Parse(input.Split('-')[0].Trim());
int max = int.Parse(input.Split('-')[1].Trim());
// inclusive
simpleList.AddRange(Enumerable.Range(min, max - min + 1));
continue;
}
if (input.Trim().EndsWith("+"))
{
infinity = true;
simpleList.Add(int.Parse(input.Trim().Trim('+')));
} else simpleList.Add(int.Parse(input.Trim()));
}
simpleList.Sort();
for (int i = 0; i < simpleList.Count; i++)
{
int currentVal = simpleList[i];
int q = i;
while (q < simpleList.Count)
{
if (q != simpleList.Count - 1 && simpleList[q] + 1 == simpleList[q + 1])
{
q++;
continue;
}
if (currentVal == simpleList[q])
{
retval.Add(currentVal.ToString());
i = q;
break;
}
if (currentVal + 1 == simpleList[q])
{
retval.Add(currentVal.ToString());
retval.Add(simpleList[q].ToString());
i = q;
break;
}
retval.Add(currentVal + "-" + simpleList[q]);
i = q;
break;
}
}
if (infinity)
retval[retval.Count - 1] = retval[retval.Count - 1] + "+";
return retval;
}测试用例:
var inputs = new List<string> {"11", "12", "13", "14-18", "2-3", "25", "82+", "9"};
var simplifiedList = Simplify(inputs);
foreach (string input in simplifiedList)
{
Console.WriteLine(input);
}输出:
2
3
9
11-18
25
82+发布于 2015-06-24 10:04:43
下面是我的一组函数。我将我的序列项定义为整数列表(都是正BTW),其中单个num是(num),range是(start end),无限范围是(num -1)。在字符串中,我允许使用-或|作为范围分隔符。我可能遗漏了几个扩展方法,但我想我得到了它们。我知道网上的空间看起来很丑陋,你需要复制并粘贴到.cs文件中才能看得清楚。我只是从VS复制粘贴过来的。
要进行测试,可以尝试这样的方法:(它们故意具有奇数的值。)
结果= AddSequences(StringToSequence("10,11,12-14,20-30,40+"),StringToSequence(“15,16,21-41,50+”);
结果= SubtractSequences(StringToSequence("10,11,20-30,40+"),StringToSequence(“21-41,50+”);
//-------------------sequence tools-----------------------------
public static string SequenceToString(List<List<int>> seq) {
string ret = "";
foreach (List<int> pair in seq) {
if (pair.Count == 1)
ret = ret + pair[0].ToString() + ",";
else {
if (pair[1] != -1)
ret = ret + pair[0].ToString() + "|" + pair[1].ToString() + ",";
else
ret = ret + pair[0].ToString() + "+,";
}
}
return ret;
}
public static List<List<int>> StringToSequence(string seq) {
List<List<int>> ret = new List<List<int>>();
//make sure we have a list of integers
//turn into a List<List<int>>
//use -1 as second item to indicate the +
List<List<int>> pairs = new List<List<int>>();
//int usesPlus = -1;
//split by commas
string[] items = seq.RemoveCharsExcept("|.,-+").Split(',');
foreach (string str in items) {
//see if we have a dash
if (str.Contains("-") || str.Contains("|")) {
string[] tmp1;
if (str.Contains("-"))
tmp1 = str.Split('-');
else
tmp1 = str.Split('|');
//the RemoveChars() is to get rid of a + if there
if (tmp1.Count() == 2 && tmp1[0].RemoveChars().IsInteger() && tmp1[1].RemoveChars().IsInteger()) {
int int1 = tmp1[0].RemoveChars().ToInteger();
int int2 = tmp1[1].RemoveChars().ToInteger();
if (int2 > int1)
if (int2 - int1 == 1) {
pairs.Add(new List<int>() { int1 });
pairs.Add(new List<int>() { int2 });
}
else
pairs.Add(new List<int>() { int1, int2 });
}
}
else if (str.RemoveChars().IsInteger()) {
int tmp = str.RemoveChars().ToInteger();
if (str.Right(1) == "+")
pairs.Add(new List<int>() { str.RemoveChars().ToInteger(), -1 });
else
pairs.Add(new List<int>() { str.RemoveChars().ToInteger() });
}
}
//now sort list by first item
ret = pairs.OrderBy(o => o[0]).ToList();
DelSequenceDupes(ret);
CombineSequenceNums(ret);
CombineSequenceMergeNumsToSeqs(ret);
CombineSequenceSeqs(ret);
TrimSequenceByPlusNums(ret);
return ret;
}
//all these assume items are in order by first element
public static List<List<int>> AddSequences(List<List<int>> origSeq, List<List<int>> addSeq) {
List<List<int>> ret = new List<List<int>>();
//add in items and clean up
origSeq.AddRange(addSeq);
//sort list by first item
ret = origSeq.OrderBy(o => o[0]).ToList();
DelSequenceDupes(ret);
CombineSequenceNums(ret);
CombineSequenceMergeNumsToSeqs(ret);
CombineSequenceSeqs(ret);
TrimSequenceByPlusNums(ret);
return ret;
}
public static List<List<int>> DelSequenceDupes(List<List<int>> seq) {
List<List<int>> ret = new List<List<int>>();
List<int> prev = new List<int>();
foreach (List<int> pair in seq) {
if (prev.Count == 0) {
ret.Add(pair);
prev = pair;
}
else if (prev.Count != pair.Count || prev[0] != pair[0] || prev[1] != pair[1]) {
ret.Add(pair);
prev = pair;
}
}
return ret;
}
public static List<List<int>> CombineSequenceNums(List<List<int>> seq) {
List<List<int>> ret = new List<List<int>>();
int conscount = 0;
int previtem = -1;
foreach (List<int> pair in seq) {
if (pair.Count == 1) {
if (conscount == 0) {
previtem = pair[0];
conscount++;
}
else {
if (pair[0] == previtem + 1) {
previtem = pair[0];
conscount++;
}
//else deal with any sequences or not, and start over
else {
if (conscount < 3) {
for (int i = conscount - 1; i >= 0; i--) {
ret.Add(new List<int>() { previtem - i });
}
}
//else its a sequence
else {
ret.Add(new List<int>() { previtem - (conscount - 1), previtem });
}
//start over on this number
previtem = pair[0];
conscount = 1;
}
}
}
else {
//if on a sequence, see if conscount is more than 2
if (conscount < 3) {
for (int i = conscount - 1; i >= 0; i--) {
ret.Add(new List<int>() { previtem - i });
}
}
//else its a sequence
else {
ret.Add(new List<int>() { previtem - (conscount - 1), previtem });
}
//start over on bogus previtem
previtem = -1;
conscount = 0;
//now add the sequence as is
ret.Add(pair);
}
}
//add any hanging numbers
//if on a sequence, see if conscount is more than 2
if (conscount < 3) {
for (int i = conscount - 1; i >= 0; i--) {
ret.Add(new List<int>() { previtem - i });
}
}
//else its a sequence
else {
ret.Add(new List<int>() { previtem - (conscount - 1), previtem });
}
return ret;
}
public static List<List<int>> CombineSequenceSeqs(List<List<int>> seq) {
List<List<int>> ret = new List<List<int>>();
List<int> prevseq = new List<int>();
foreach (List<int> pair in seq) {
if (pair.Count == 1) {
//add previous sequence if any
if (prevseq.Count > 0) {
ret.Add(prevseq);
prevseq = new List<int>();
}
ret.Add(pair);
}
//else if a sequence
else {
if (pair[1] == -1) {
//add previous sequence if any
if (prevseq.Count > 0) {
ret.Add(prevseq);
prevseq = new List<int>();
}
ret.Add(pair);
}
else {
if (prevseq.Count == 0) {
prevseq = pair;
}
//if adjacent or any overlap, combine
else {
if (prevseq[1] + 1 >= pair[0]) {
prevseq = new List<int>() { prevseq[0], Math.Max(pair[1], prevseq[1]) };
}
else {
ret.Add(prevseq);
prevseq = pair;
}
}
}
}
}
//add at end
if (prevseq.Count > 0)
ret.Add(prevseq);
return ret;
}
public static List<List<int>> CombineSequenceMergeNumsToSeqs(List<List<int>> seq) {
List<List<int>> ret = new List<List<int>>();
int index = 0;
while (index < seq.Count) {
List<int> pair = seq[index];
//if a number, add to ret
if (pair.Count == 1 || (pair.Count == 2 && pair[1] == -1)) {
ret.Add(pair);
index++;
}
else {
//if on a seq, look behind and ahead for numbers to gobble
int lookback = 1;
List<int> newpair = pair;
bool go = true;
while (go &&
index > 0 &&
index - lookback > -1) {
if (seq[index - lookback].Count == 1 &&
seq[index - lookback][0] == newpair[0] - 1) {
//remove last item from ret
ret.RemoveAt(ret.Count - 1);
//modify newpair
newpair[0] = newpair[0] - 1;
lookback++;
}
else
go = false;
}
//now look ahead, careful to get rid of item in the range already
int lookahd = 1;
go = true;
while (go &&
index < seq.Count + 1 &&
index + lookahd < seq.Count) {
if (seq[index + lookahd].Count == 1) {
//if in range already
if (seq[index + lookahd][0] <= newpair[1])
lookahd++;
else if (seq[index + lookahd][0] == newpair[1] + 1) {
//modify newpair
newpair[1] = newpair[1] + 1;
lookahd++;
}
else
go = false;
}
else
go = false;
}
//add newpair to ret
ret.Add(newpair);
//jump past items done
index = index + lookahd;
}
}
return ret;
}
public static List<List<int>> TrimSequenceByPlusNums(List<List<int>> seq) {
List<List<int>> ret = new List<List<int>>();
//get sequence info
int lowPlsNum;
int highest = FindHighestInSeq(seq, out lowPlsNum);
if (lowPlsNum != -1) {
foreach (List<int> pair in seq) {
if (pair.Count == 1) {
if (pair[0] < lowPlsNum)
ret.Add(pair);
}
else {
if (pair[1] == -1) {
if (pair[0] == lowPlsNum)
ret.Add(pair);
}
else {
if (pair[1] < lowPlsNum) {
ret.Add(pair);
}
else if (pair[0] < lowPlsNum && pair[1] >= lowPlsNum)
ret.Add(new List<int>() { pair[0], lowPlsNum - 1 });
}
}
}
}
else
ret = seq;
return ret;
}
//assumes subtSeq has been cleaned so items are in order
public static List<List<int>> SubtractSequences(List<List<int>> origSeq, List<List<int>> subtSeq) {
List<List<int>> ret = new List<List<int>>();
if (subtSeq.Count > 0) {
//go through origSeq and modify any items
foreach (List<int> pair in origSeq) {
//case 1 - just one number
if (pair.Count == 1) {
if (!IsPtInSequence(subtSeq, pair[0]))
//add if not in subt sequence
ret.Add(pair);
}
//case 2 - a sequence in orig
else if (pair.Count == 2 && pair[1] != -1) {
//must chop up based on items in subt
List<List<int>> res = SubtractFromNonPlusSequence(pair, subtSeq);
if (res.Count > 0)
ret.AddRange(res);
}
//a number+
else if (pair.Count == 2 && pair[1] == -1) {
List<List<int>> res = SubtractFromPlusSequence(pair, subtSeq);
if (res.Count > 0)
ret.AddRange(res);
}
}
}
return ret;
}
//subtract a num+ by sequence
//origSeq must have a -1 as second item
public static List<List<int>> SubtractFromPlusSequence(List<int> origSeq, List<List<int>> subtSeq) {
List<List<int>> ret = new List<List<int>>();
//handle by converting the num+ to a sequence plus a num+ if needed
//find largest number in subtSeq
int lowPlsNum;
int largest = FindHighestInSeq(subtSeq, out lowPlsNum);
List<int> tmpseq;
//now make temp sequence
if (lowPlsNum == -1) {
//return original as its all before
if (largest < origSeq[0]) {
ret = new List<List<int>>() { origSeq };
}
else {
//if overlap of 1
if (largest - origSeq[0] == 1) {
if (!IsPtInSequence(subtSeq, origSeq[0]))
ret.Add(new List<int>() { origSeq[0] });
}
else if (largest - origSeq[0] == 2) {
if (!IsPtInSequence(subtSeq, origSeq[0]))
ret.Add(new List<int>() { origSeq[0] });
if (!IsPtInSequence(subtSeq, origSeq[0] + 1))
ret.Add(new List<int>() { origSeq[0] + 1 });
}
else {
tmpseq = new List<int>() { origSeq[0], largest - 1 };
ret.AddRange(SubtractFromNonPlusSequence(tmpseq, subtSeq));
}
//add a plus after all, since subtSeq did not have a +num in it
ret.Add(new List<int>() { largest + 1, -1 });
}
}
else {
//its got a plus in it, just do before the subtract +
if (lowPlsNum - origSeq[0] == 1) {
ret.Add(new List<int>() { origSeq[0] });
}
else if (lowPlsNum - origSeq[0] == 2) {
ret.Add(new List<int>() { origSeq[0] });
ret.Add(new List<int>() { origSeq[0] + 1 });
}
else {
tmpseq = new List<int>() { origSeq[0], lowPlsNum - 1 };
ret.AddRange(SubtractFromNonPlusSequence(tmpseq, subtSeq));
}
//else return blank as it got wiped out
}
return ret;
}
//subtract a sequence (2 items) using another
public static List<List<int>> SubtractFromNonPlusSequence(List<int> origSeq, List<List<int>> subtSeq) {
List<List<int>> ret = new List<List<int>>();
//as we go along, curseq will be the term at hand to possibly chop
List<int> curseq = origSeq;
bool done = false;
foreach (List<int> chopr in subtSeq) {
if (!done) {
//if chopping with one number
if (chopr.Count == 1) {
#region Chop with one
//test if chop at all
if (chopr[0] < curseq[0] || chopr[0] > curseq[1]) {
ret.Add(curseq);
done = true;
}
else {
//handle left side of chop
if (chopr[0] - curseq[0] == 1) {
ret.Add(new List<int>() { curseq[0] });
}
else if (chopr[0] - curseq[0] == 2) {
ret.Add(new List<int>() { curseq[0] });
ret.Add(new List<int>() { curseq[0] + 1 });
}
else if (chopr[0] - curseq[0] > 2) {
ret.Add(new List<int>() { curseq[0], chopr[0] - 1 });
}
//handle right side of chop
if (curseq[1] - chopr[0] == 1) {
ret.Add(new List<int>() { curseq[1] });
done = true;
}
else if (curseq[1] - chopr[0] == 2) {
ret.Add(new List<int>() { curseq[1] - 1 });
ret.Add(new List<int>() { curseq[1] });
done = true;
}
else if (curseq[1] - chopr[0] > 2) {
curseq = new List<int>() { chopr[0] + 1, curseq[1] };
}
}
}
#endregion
//now look at a chopper sequence
else {
//if a number +
if (chopr[1] == -1) {
#region Chop with one+
//only 3 cases matter
//if at or before start
if (chopr[0] <= curseq[0]) {
//stop
done = true;
}
else if (chopr[0] > curseq[1]) {
//do nothing
}
//if past start by 1
else if (chopr[0] == curseq[0] + 1) {
ret.Add(new List<int>() { curseq[0] });
done = true;
}
//if past start by 2
else if (chopr[0] == curseq[0] + 2) {
ret.Add(new List<int>() { curseq[0] });
ret.Add(new List<int>() { curseq[0] + 1 });
//stop here because discard the rest
done = true;
}
//if past start by more than 2
else {
ret.Add(new List<int>() { curseq[0], chopr[0] - 1 });
done = true;
}
}
#endregion
//if a sequence
else {
#region Chop with seq
//complete overlap
if (curseq[0] >= chopr[0] && curseq[1] <= chopr[1]) {
done = true;
}
//if we overlap chop start
else if (chopr[1] == curseq[0]) {
curseq = new List<int>() { curseq[0] + 1, curseq[1] };
}
//if we overlap chop end
else if (chopr[0] == curseq[1]) {
curseq = new List<int>() { curseq[0], curseq[1] - 1 };
}
//if we enclose chopper
else if (chopr[0] > curseq[0] && chopr[1] < curseq[1]) {
//handle left side
if (chopr[0] - curseq[0] == 1) {
ret.Add(new List<int>() { curseq[0] });
}
else if (chopr[0] - curseq[0] == 2) {
ret.Add(new List<int>() { curseq[0] });
ret.Add(new List<int>() { curseq[0] + 1 });
}
else {
ret.Add(new List<int>() { curseq[0], chopr[0] - 1 });
}
//handle right side
if (curseq[1] - chopr[1] == 1) {
ret.Add(new List<int>() { curseq[1] });
done = true;
}
else if (curseq[1] - chopr[1] == 2) {
ret.Add(new List<int>() { curseq[1] - 1 });
ret.Add(new List<int>() { curseq[1] });
done = true;
}
else {
curseq = new List<int>() { chopr[1] + 1, curseq[1] };
}
}
//if we overlap past chop start
else if (chopr[0] < curseq[0] && chopr[1] > curseq[0] && chopr[1] < curseq[1]) {
//see if we leave nums or a sequence
if (curseq[1] - chopr[1] == 1) {
ret.Add(new List<int>() { curseq[1] });
done = true;
}
else if (curseq[1] - chopr[1] == 2) {
ret.Add(new List<int>() { curseq[1] - 1 });
ret.Add(new List<int>() { curseq[1] });
done = true;
}
else {
curseq = new List<int>() { chopr[1] + 1, curseq[1] };
}
}
//if we overlap before chop end
else if (chopr[0] > curseq[0] && chopr[0] < curseq[1] && chopr[1] >= curseq[1]) {
//see if we leave nums or a sequence
if (chopr[0] - curseq[0] == 1) {
ret.Add(new List<int>() { curseq[0] });
done = true;
}
else if (chopr[0] - curseq[0] == 2) {
ret.Add(new List<int>() { curseq[0] });
ret.Add(new List<int>() { curseq[0] + 1 });
done = true;
}
else {
ret.Add(new List<int>() { curseq[0], chopr[0] - 1 });
done = true;
}
}
}
#endregion
}
}
}
if (!done)
ret.Add(curseq);
return ret;
}
//find highest number in sequence, as well as lowest +num if an
//lowPlsNum is -1 if not found
public static int FindHighestInSeq(List<List<int>> seq, out int lowPlsNum) {
//find largest number in subtSeq
int ret = 0;
//track lowest num+ if found in subtSeq
lowPlsNum = -1;
foreach (List<int> pair in seq) {
if (pair.Count == 1) {
if (pair[0] > ret)
ret = pair[0];
}
else if (pair.Count == 2 && pair[1] != -1) {
if (pair[1] > ret)
ret = pair[1];
}
else if (pair.Count == 2 && pair[1] == -1) {
if (lowPlsNum == -1)
lowPlsNum = pair[0];
if (pair[0] < lowPlsNum)
lowPlsNum = pair[0];
}
}
return ret;
}
public static bool IsPtInSequence(List<List<int>> seq, int ptnum) {
bool ret = false;
foreach (List<int> lst in seq) {
if (lst.Count == 1) {
if (lst[0] == ptnum)
ret = true;
}
else if (lst.Count == 2) {
//check if plus item
if (lst[1] == -1) {
if (ptnum >= lst[0])
ret = true;
}
else if (ptnum >= lst[0] && ptnum <= lst[1])
ret = true;
}
}
return ret;
}
public static string RemoveChars(this string s) {
string str = "";
foreach (char c in s) {
if (char.IsDigit(c) || c == '.' || c == ',' || c == '-') {
str = str + c.ToString();
}
}
return str;
}
//keep is list of single chars
public static string RemoveCharsExcept(this string s, string keep) {
string str = "";
foreach (char c in s) {
if (char.IsDigit(c) || keep.Contains(c)) {
str = str + c.ToString();
}
}
return str;
}
/// <summary>
/// Returns the last few characters of the string with a length
/// specified by the given parameter. If the string's length is less than the
/// given length the complete string is returned. If length is zero or
/// less an empty string is returned
/// </summary>
/// <param name="s">the string to process</param>
/// <param name="length">Number of characters to return</param>
/// <returns></returns>
public static string Right(this string s, int length) {
length = Math.Max(length, 0);
if (s.Length > length) {
return s.Substring(s.Length - length, length);
}
else {
return s;
}
}
/// <summary>
/// Returns the first few characters of the string with a length
/// specified by the given parameter. If the string's length is less than the
/// given length the complete string is returned. If length is zero or
/// less an empty string is returned
/// </summary>
/// <param name="s">the string to process</param>
/// <param name="length">Number of characters to return</param>
/// <returns></returns>
public static string Left(this string s, int length) {
length = Math.Max(length, 0);
if (s.Length > length) {
return s.Substring(0, length);
}
else {
return s;
}
}
public static string StripLeft(this string s, int length) {
length = Math.Max(length, 0);
if (s.Length > length) {
return s.Substring(length);
}
else {
return "";
}
}
public static string StripRight(this string s, int length) {
length = Math.Max(length, 0);
if (s.Length > length) {
return s.Substring(0, s.Length - length);
}
else {
return "";
}
}发布于 2015-06-20 02:31:54
您暗示您有三个不同的类来表示三种不同类型的范围。我希望你有一个单一的聚合范围集合类?如果没有,请创建一个。下面是一个伪代码算法,用于在向现有集合添加新集合时执行以下操作:
Add(RangeCollection collection2)
for each int n in collection2.singles
if n >= infinite_range_start: next n
// there should only be one infinite range
for each range r in ranges // ranges should be a sorted list
if n = r.start - 1
r.start = n
next n
if n = r.end + 1
r.end = n
next n
if n < r.end: break
if n >= r.start and n <= range.end: next n
// at this point we know n is not within any ranges
singles.Add(n) // should be a set
CheckSinglesForRanges()
MergeOverlappingRanges()
CheckInfiniteRange()
CheckSinglesForRanges()
singleList = singles.ToOrderedList()
start = null
end = null
for each number n in singleList
if start = null
start = n
next n
if n = start + 1
end = n
next n
if start != null and end != null and end > start + 1
ranges.Add(new range(start, end))
start = null
end = null
if start != null and end != null and end > start + 1
ranges.Add(new range(start, end))
MergeOverLappingRanges()
// ranges should be a list of range objects ordered by range.start
prevR = null
for each range r in ranges
if prevR = null
prevR = r
next r
if prevR.end >= r.start
prevR.end = r.end
ranges.Remove(r)
next r
prevR = r
CheckInfiniteRange()
if singles.largest = inifinite_range_start - 1
inifinite_range_start--
CheckInfiniteRange()
if ranges.last.end >= inifinite_range_start - 1
inifinite_range_start = ranges.last.start
ranges.remove(ranges.last)
singles.RemoveAll(where n >= infinite_range_start)
CheckInfiniteRange()
Subtract(RangeCollection collection2)
for each number n in collection2.singles
if singles.Contains(n)
singles.remove(n)
next n
for each range r in ranges
if n = r.start
r.start++
next n
if n = r.end
r.end--
next n
if n > r.start and n < r.end:
if n = r.start + 1
singles.add(r.start)
ranges.add(new range(n + 1, r.end))
if n = r.end - 1
singles.add(r.end)
ranges.add(new range(n.start, n - 1))
else
ranges.add(new range(r.start, n - 1))
ranges.add(new range(n + 1, r.end))
ranges.Remove(r)
next n
if n = infinite_range_start
infinite_range_start++
next n
if n = infinite_range_start + 1
singles.add(infinite_range_start)
infinite_range_start = n + 1
next n
if n > infinite_range_start
ranges.add(new range(infinite_range_start, n - 1))
infinite_range_start = n + 1
next n备注:
,则镜像无限范围代码相对简单
https://stackoverflow.com/questions/30942859
复制相似问题