单独的数字范围,如果按顺序,然后是连字符,如果顺序中断则发生逗号字符

我有一个字符串表示页面nos,如1,2,3,4,8,9,10,15

我想将它显示为1-4,8-10,15即序列中的数字由连字符分隔,连字符由最小和最大数字依次包围。

如果按顺序中断,则范围用逗号分隔。

 string pageNos = "5,6,7,9,10,11,12,15,16"; string result=string.Empty; string[] arr1 = pageNos.Split(','); int[] arr = new int[arr1.Length]; for (int x = 0; x < arr1.Length; x++) // Convert string array to integer array { arr[x] = Convert.ToInt32(arr1[x].ToString()); } for (int i = 0; i < arr.Length;i++) { for (int j = i + 1; ; j++) if (arr[i] == (arr[j] - 1)) result += arr[i].ToString() + "-" + arr[j].ToString(); else result += arr[i].ToString() + ","; } Console.WriteLine(result); 

我认为循环内循环使事情变得更加混乱。 尝试只使用一个循环,因为您只需要遍历整个列表一次。

 int start,end; // track start and end end = start = arr[0]; for (int i = 1; i < arr.Length; i++) { // as long as entries are consecutive, move end forward if (arr[i] == (arr[i - 1] + 1)) { end = arr[i]; } else { // when no longer consecutive, add group to result // depending on whether start=end (single item) or not if (start == end) result += start + ","; else result += start + "-" + end + ","; start = end = arr[i]; } } // handle the final group if (start == end) result += start; else result += start + "-" + end; 

演示: http : //ideone.com/7HdpS7

一点点LINQ会整理一下:

 static IEnumerable> GetRanges(IEnumerable source) { bool started = false; int rangeStart = 0, lastItem = 0; foreach (int item in source) { if (!started) { rangeStart = lastItem = item; started = true; } else if (item == lastItem + 1) { lastItem = item; } else { yield return new Tuple(rangeStart, lastItem); rangeStart = lastItem = item; } } if (started) { yield return new Tuple(rangeStart, lastItem); } } static string FormatRange(Tuple range) { string format = (range.Item1 == range.Item2) ? "{0:D}" : "{0:D}-{1:D}"; return string.Format(format, range.Item1, range.Item2); } string pageNos = "5,6,7,9,10,11,12,15,16"; int[] pageNumbers = Array.ConvertAll(pageNos.Split(','), Convert.ToInt32); string result = string.Join(",", GetRanges(pageNumbers).Select(FormatRange)); 

您可以使用此方法获取相邻的数字组,其中每个组由自定义Range -class表示:

 class Range { public int? Start { get; set; } public int? End { get; set; } } private static IEnumerable getAdjacentRanges(IEnumerable nums) { var ranges = new List(); if (!nums.Any()) return ranges; var ordered = nums.OrderBy(i => i); int lowest = ordered.First(); int last = lowest; ranges.Add(new Range { Start = lowest }); foreach (int current in ordered) { lastRange = ranges[ranges.Count - 1]; if (current > last + 1) { lastRange.End = last; ranges.Add(new Range { Start = current }); } last = current; } return ranges; } 

其余的很简单:

 var arr = new[] { 1, 2, 3, 4, 8, 9, 10, 15 }; var ranges = getAdjacentRanges(arr) .Select(r => r.End.HasValue ? string.Format("{0}-{1}", r.Start, r.End) : r.Start.ToString()); Console.Write(string.Join(",", ranges)); 

输出: 1-4,8-10,15

DEMO

 string pageNos = "5,6,7,9,10,11,12,15,16"; string[] arr1 = pageNos.Split(','); int[] arr = new int[arr1.Length]; for (int x = 0; x < arr1.Length; x++) // Convert string array to integer array { arr[x] = Convert.ToInt32(arr1[x]); } StringBuilder sb = new StringBuilder(); bool hyphenOpen = false; for (int i = 0; i < arr.Length - 1; i++) { if (arr[i] + 1 == arr[i+1]) { if (!hyphenOpen) { hyphenOpen = true; sb.Append(arr[i] + "-"); } } else { hyphenOpen = false; sb.Append(arr[i] + ","); } } sb.Append(arr[arr.Length-1]); Console.WriteLine(sb.ToString()); 

这很长而且很笨重,但它确实有效。

PS - 我按原样离开了OP的原始字符串 - > int,请参阅JonB关于更清晰方法的评论。

我不是C#人,但我猜你有问题:

  if (arr[i] == (arr[j] - 1)) result += arr[i].ToString() + "-" + arr[j].ToString(); 

你不应该在你的结果中添加它。 但设置一个标志(可能是布尔值),表示现在我开始计数了。

如果flag == ture且数字不再连续,那么就是添加到结果中的时间,当然是“ – ”。

 public static string HyphenateRanges(this string input) { if (string.IsNullOrEmpty(input)) { return ""; } var orderedDistinct = input.Split(',') .Select(Int32.Parse) .Distinct() .OrderBy(x => x) .ToArray(); Func replaceRangeValuesWithDash = (x, i) => i == 0 || // first i == orderedDistinct.Length - 1 || // last orderedDistinct[i + 1] - orderedDistinct[i - 1] != 2 // not in a range ? x.ToString() : "-"; var rangeValuesDashed = orderedDistinct .Select(replaceRangeValuesWithDash) .ToList(); var extraDashesRemoved = rangeValuesDashed .Where((x, i) => i == 0 || rangeValuesDashed[i - 1] != x) .ToArray(); var formattedString = String.Join(",", extraDashesRemoved) .Replace(",-,", "-"); return formattedString; } 

这是一个不同的解决方案,它创建一个List>其中包含每个非顺序值以及List>的连续值的数量。 然后使用string.Join将其转换为字符串。

 string pageNos = "1,2,3,4,8,9,10,15"; // Get list of numbers as ints var list = pageNos.Split(',').Select(i => Convert.ToInt32(i)).ToList(); // Get a list of numbers and ranges of consecutive numbers var ranges = new List>(); int start = 0; for (int i = 0; i < list.Count; i++) { // First item always starts a new range if (i == 0) { start = list[i]; } // Last item always ends the current range if (i == list.Count - 1) { if (list[i] == list[i - 1] + 1) { ranges.Add(new Tuple(start, list[i] - start)); } else { ranges.Add(new Tuple(start, list[i - 1] - start)); ranges.Add(new Tuple(list[i], 0)); } } // End the current range if nonsequential if (i > 0 && i < list.Count - 1 && list[i] != list[i - 1] + 1) { ranges.Add(new Tuple(start, list[i - 1] - start)); start = list[i]; } } // Craete the result string var result = string.Join(", ", ranges.Select(r => r.Item2 == 0 ? r.Item1.ToString() : string.Format("{0}-{1}", r.Item1, r.Item1 + r.Item2))); 

使用此帮助程序类在数字列表和范围字符串之间来回转换。

这将从此处复制ConvertRangeStringToNumberList()实现, ConvertRangeStringToNumberList()从此处 ConvertNumberListToRangeString() ,稍作改进。

 using System; using System.Collections.Generic; using System.Linq; public static class NumberRangeHelper { ///  /// Converts a string of comma separated list of numbers and ranges to the list of individual numbers it represents. ///  /// Range in form of "2,4-8,11,15-22,39" /// A list of numbers public static List ConvertRangeStringToNumberList(string numbers) { var numbersSplit = numbers.Split(','); var convertedNumbers = new SortedSet(); foreach (var strNumber in numbersSplit) { int number; if (int.TryParse(strNumber, out number)) { convertedNumbers.Add(number); } else { // try and delimited by range if (strNumber.Contains('-')) { var splitRange = strNumber.Split('-'); if (splitRange.Length == 2) { int firstNumber; int secondNumber; if (Int32.TryParse(splitRange[0], out firstNumber) && Int32.TryParse(splitRange[1], out secondNumber)) { for (var i = firstNumber; i <= secondNumber; ++i) { convertedNumbers.Add(i); } } } } } } return convertedNumbers.ToList(); } ///  /// Converts a list of numbers to their concise range representation. ///  /// A list of numbers such as new[] { 1, 2, 3, 4, 5, 12, 13, 14, 19 } /// A string like "1-5, 12-14, 19" public static string ConvertNumberListToRangeString(IEnumerable numbers) { var items = new SortedSet(numbers) .Select((n, i) => new { number = n, group = n - i }) .GroupBy(n => n.group) .Select(g => (g.Count() >= 3) ? g.First().number + "-" + g.Last().number : String.Join(", ", g.Select(x => x.number)) ) .ToList(); return String.Join(", ", items); } } 

测试:

 Action> DumpList = l => Console.WriteLine("\t[{0}]", String.Join(", ", l)); Action DumpRange = s => Console.WriteLine("\t\"{0}\"", s); var numbers = new[] { 1, 1, 2, 3, 4, 5, 12, 13, 19, 19, 6, 7 }; DumpList(numbers); var str = ConvertNumberListToRangeString(numbers); DumpRange(str); var list = ConvertRangeStringToNumberList(str); DumpList(list); Console.WriteLine(); str = "1-5, 12, 13, 19, 20, 21, 2-7"; DumpRange(str); list = ConvertRangeStringToNumberList(str); DumpList(list); str = ConvertNumberListToRangeString(list); DumpRange(str); 

输出:

 [1, 1, 2, 3, 4, 5, 12, 13, 19, 19, 6, 7] "1-7, 12, 13, 19" [1, 2, 3, 4, 5, 6, 7, 12, 13, 19] "1-5, 12, 13, 19, 20, 21, 2-7" [1, 2, 3, 4, 5, 6, 7, 12, 13, 19, 20, 21] "1-7, 12, 13, 19-21"