Usa LINQ per raggruppare una sequenza di numeri senza spazi vuoti

Con questo array int[]{ 1, 2, 3, 4, 7, 8, 11, 15,16,17,18 }; Come posso convertire in questo array di stringhe "1-4","7-8","11","15-18"

Suggerimenti? Linq?

 var array = new int[] { 1, 2, 3, 4, 7, 8, 11, 15, 16, 17, 18 }; var result = string.Join(",", array .Distinct() .OrderBy(x => x) .GroupAdjacentBy((x, y) => x + 1 == y) .Select(g => new int[] { g.First(), g.Last() }.Distinct()) .Select(g => string.Join("-", g))); 

con

 public static class LinqExtensions { public static IEnumerable> GroupAdjacentBy( this IEnumerable source, Func predicate) { using (var e = source.GetEnumerator()) { if (e.MoveNext()) { var list = new List { e.Current }; var pred = e.Current; while (e.MoveNext()) { if (predicate(pred, e.Current)) { list.Add(e.Current); } else { yield return list; list = new List { e.Current }; } pred = e.Current; } yield return list; } } } } 

Non hai bisogno di Linq; infatti, la soluzione più semplice richiede la conoscenza di tre posizioni nell’array (il numero iniziale, il numero corrente e il numero successivo dopo l’attuale), per cui gli Enumerables non sono adatti.

Prova questo:

 var start = 0; var end = 0; var write = false; var builder = new StringBuilder(); for(var i=0; i array[i] + 1) { end = i; write = true; } if(write) { if(end - start == 0) //one number builder.Append(String.Format("{0}, ", array[start]); else //multi-number range builder.Append(String.Format("{0}-{1}, ", array[start], array[end]); start = i+1; end = i+1; //not really necessary but avoids any possible case of counting backwards write = false; } } 

Puoi riorganizzare questo per ridurre il nidificazione del codice, continue presto nella logica del loop e rimuovere alcuni vars; guadagnerai qualche millesimo di tempo di esecuzione. Dovrai anche tagliare gli ultimi due caratteri (una virgola e uno spazio finale) dalla fine dello StringBuilder prima di estrarre la stringa.

Qual è l’algoritmo che vuoi implementare? Scopri cosa vuoi che accada, quindi verifica se può essere reso più chiaro con una traduzione LINQ. Ecco qualcosa di non LINQ che potrebbe darti un’idea.

 int[] array = { 1, 2, 3, 4, 7, 8, 11, 15, 16, 17, 18}; List ranges = new List(); // code assumes array is not zero-length, is distinct, and is sorted. // to do: handle scenario as appropriate if assumptions not valid Action> addToRanges = (first, last, list) => { if (last == first) list.Add(last.ToString()); else list.Add(string.Format("{0}-{1}", first, last)); ; }; int firstItem = array[0]; int lastItem = firstItem; foreach (int item in array.Skip(1)) { if (item > lastItem + 1) { addToRanges(firstItem, lastItem, ranges); firstItem = lastItem = item; } else { lastItem = item; } } addToRanges(firstItem, lastItem, ranges); // return ranges or ranges.ToArray() 

Ecco un taglio a questo:

 public static IEnumerable ToRanges(this IEnumerable values) { int? start = null, end = null; foreach (var value in values.OrderBy(vv => vv)) { if (!start.HasValue) { start = value; } else if (value == (end ?? start) + 1) { end = value; } else { yield return end.HasValue ? String.Format("{0}-{1}", start, end) : String.Format("{0}", start); start = value; end = null; } } if (start.HasValue) { yield return end.HasValue ? String.Format("{0}-{1}", start, end) : String.Format("{0}", start); } }