Intervallo di numeri separato, se in sequenza, quindi con trattino, e se si verifica una sequenza in sequenza, allora carattere virgola

Ho una stringa che indica pagine come 1,2,3,4,8,9,10,15 .

Voglio che questo sia mostrato come 1-4,8-10,15 cioè i numeri in sequenza sono separati da un trattino racchiuso dal numero più piccolo e più grande in sequenza.

Se si interrompe in sequenza, l’intervallo deve essere separato dalla virgola.

 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); 

Penso che il loop-in-loop stia rendendo le cose più confuse. Prova a utilizzare solo un singolo ciclo, perché devi solo scorrere l’intero elenco una sola volta.

 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; 

Demo: http://ideone.com/7HdpS7

Un po ‘di LINQ lo riordina:

 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)); 

È ansible utilizzare questo metodo per ottenere gruppi di numeri adiacenti in cui ciascun gruppo è rappresentato da una class Range :

 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; } 

Il resto è facile:

 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)); 

uscita: 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()); 

Questo è lungo e goffo, ma funziona.

PS - Ho lasciato la stringa originale dell'OP-> int così com'è, vedi il commento di JonB sulla domanda per un metodo molto più pulito.

non sono una persona C #, ma immagino che tu abbia un problema:

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

non dovresti aggiungerlo nel risultato. ma imposta una bandiera (forse booleana), per indicare che ora inizio a contare.

se la bandiera == ture e il numero non è più continuo, è il momento di aggiungere al risultato, ovviamente con “-“.

 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; } 

Ecco una soluzione diversa che crea un List> con ogni valore non sequenziale e il numero di valori sequenziali che lo seguono. Questo viene quindi trasformato in una stringa usando 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))); 

Utilizza questa class helper per convertire avanti e indietro tra elenchi di numeri e stringhe di intervallo.

Questo copia l’implementazione di ConvertRangeStringToNumberList() da qui e ConvertNumberListToRangeString() da qui con lievi miglioramenti.

 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); } } 

Test:

 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); 

Produzione:

 [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"