2010-09-21 12 views
7

Sto cercando un modo per calcolare l'intervallo di un set di numeri, ad esempio.Ottieni intervallo di numeri interi con linq

se avessi H555, H567, H589, H590, H591, H592, H593, H594, H595, H596, H597

Vorrei uscita del H555, H567, H589-H597.

Ho esaminato le domande pertinenti e non riesco a trovare nulla di simile a quello che sto cercando.

Grazie

+7

Do deve essere con LINQ? –

+0

Che cos'è quell'insieme di numeri? Una stringa? Un array? –

+0

Sono aperto a qualsiasi soluzione. è un insieme di banconote per essere esatti come H272 per il conto della casa 272, ma essenzialmente un insieme di stringhe – Jesse

risposta

4

Credo che LINQ è davvero in testa qui, ma se si desidera che qui si sono:

 int[] arr = { 555, 567, 589, 590, 591, 592, 593, 594, 595, 596, 597 }; 
     int gr = 0; 
     var q = arr 
      .Skip(1) 
      .Select((x, i) => new { x, group = (x - arr[i]) == 1 ? gr : gr++ }) 
      .GroupBy(a => a.group) 
      .Select(
       a => a.Count() == 1 
        ? a.First().x.ToString() 
        : string.Format("{0}-{1}", a.First().x, a.Last().x)); 
     foreach (var item in q) 
     { 
      Console.Write(item); 
      Console.Write(", "); 
     } 
+0

Pensa che posso farlo funzionare. Grazie – Jesse

+2

@Jesse bene, personalmente preferisco la risposta di Jon. È migliore in termini di prestazioni sia della CPU che della memoria. Volevo solo mostrare come puoi farlo in Linq, non significa che dovresti farlo in Linq. – Andrey

+0

Concordo sul fatto che la risposta di Jon sia più performante, ma nel mio caso questo è esattamente quello che stavo cercando. – Jesse

8

Beh, mi piacerebbe fare qualcosa di simile:

public sealed class Range 
{ 
    public int Low { get; private set; } 
    public int High { get; private set; } 

    public Range(int low, int high) 
    { 
     this.Low = low; 
     this.High = high; 
    } 
} 

Poi (completamente testato, non può anche compilare, ma spero che si otterrà la deriva):

public static IEnumerable<Range> FindRanges(IEnumerable<int> values) 
{ 
    using (IEnumerator<int> iterator = values.GetEnumerator()) 
    { 
     if (!iterator.MoveNext()) 
     { 
      yield break; 
     } 
     int low = iterator.Current; 
     int high = low; 
     while (iterator.MoveNext()) 
     { 
      int next = iterator.Current; 
      if (next > high + 1) 
      { 
       // Previous range (or possibly single value) has finished 
       yield return new Range(low, high); 
       low = next; 
      } 
      high = next; 
     } 
     // Yield trailing range 
     yield return new Range(low, high); 
    } 
} 

Non penso che questo sia particolarmente facile da usare usando LINQ diretto, per essere onesti.

EDIT: Per adattare questo, ora che tutto comincia con H, basta usare:

var numbers = strings.Select(x => int.Parse(x.Substring(1)); 
var ranges = FindRanges(numbers); 

var rangeStrings = ranges.Select(r => r.High == r.Low 
            ? "H" + r.Low : "H" + r.Low + "-" + r.High); 
var result = string.Join(",", rangeStrings); 
+0

Sarebbe stato buono fino a quando non ha aggiunto "H" all'inizio di ogni elemento. –

+0

Forse usa la H come chiave in un dizionario, int come valore, calcola l'intervallo e poi riassembla? – Jesse

+0

@Jesse: Quello che descrivi creerebbe un dizionario in cui ogni chiave era la stessa (cioè non unica). Perché non dare per scontato H, quindi inserire gli interi in SortedList? –

Problemi correlati