我正在编写一个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?这不是微不足道的。我对任何解决方案持开放态度,如果需要,我可以导入库。
答案 0 :(得分:0)
这是我写的一个小功能,可以帮助你...... 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+
答案 1 :(得分:0)
所以这是我的一组功能。 我将序列项定义为整数列表(所有正BTW),其中单个num是(num),range是(start end),无限范围是(num -1)。 在字符串中,我允许 - 或|用于范围分隔符。 我可能省略了几种扩展方法,但我认为我得到了它们。 我知道这些空间在网上看起来很难看,你需要复制并粘贴到.cs文件中才能看得很清楚。我jsut从VS复制和粘贴。
进行测试,尝试这样的事情:(他们故意有奇数值......)
列表&gt; result = AddSequences(StringToSequence(“10,11,12-14,20-30,40 +”),StringToSequence(“15,16,21-41,50 +”));
列表&gt; result = SubtractSequences(StringToSequence(“10,11,20-30,40 +”),StringToSequence(“21-41,50 +”));
列表&gt; result = StringToSequence(“1-5,8,10,11-29,30 +,19-25,30-40,50 +,60 +”);
//-------------------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 "";
}
}
答案 2 :(得分:-1)
您提示您有三个不同的类,代表三种不同类型的范围。我希望你有一个聚合范围集合类?如果没有,请创建一个。这是一个伪代码算法,用于在将新集添加到现有集时执行的操作:
parser.add_argument("-a", "--action", nargs='*', action="store", help="do some action")
args = parser.parse_args()
if args.action is not None:
if len(args.action) not in (0, 2):
parser.error('Specify no or two actions')
# action was specified but either there were two actions or no action
else:
# action was not specified
注意: