2010-09-21 13 views
7

Örneğin bir sayı kümesinin aralığını hesaplamanın bir yolunu arıyorum. Ben H555, H567, H589, H590, H591, H592, H593, H594, H595, H596, H597Linq ile tamsayılar aralığı alın

olsaydı

Ben H555, H567, H589-H597 çıktısını istiyorum.

İlgili sorulara göz attım ve aradığım şey gibi bir şey bulamıyorum.

Teşekkür

+7

Do LINQ ile olmalı? –

+0

Bu sayı kümesi nedir? Dizi? Bir dizi mi? –

+0

Çözüme ne olursa olsun açığım. Bir dizi fatura, ev faturası 272 için H272 gibi, ama aslında bir dizi dizgiler – Jesse

cevap

4

Linq burada gerçekten havai olduğunu düşünüyorum ama buradan istiyorsanız şunlardır: her şeyin H ile başlar şimdi bu uyum için, sadece kullanmak

 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

Bunu işe alabileceğimi düşünüyorum. Teşekkürler – Jesse

+2

@Jesse, kişisel olarak Jon'un cevabını tercih ediyorum. CPU ve bellek performansı açısından daha iyidir. Sadece bunu Linq'de nasıl yapabileceğinizi göstermek istedim, bunu Linq'de yapmanız gerektiği anlamına gelmiyor. – Andrey

+0

Jon'un cevabının daha iyi olduğunu kabul ediyorum, ama benim durumum için bu tam da aradığım şey. – Jesse

8

Peki, böyle bir şey yapacağını: Sonra

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

(tamamen denenmemiş, hatta derlemek olmayabilir, ama umarım sürüklenme alırsınız):

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

Bunun dürüst olmak gerekirse düz LINQ kullanmanın özellikle kolay olduğunu düşünmüyorum.

DÜZENLEME:

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

Her bir öğenin başına "H" ekleyene kadar iyi olurdu. –

+0

Belki de H'yi bir Sözlük'te anahtar olarak değer olarak kullanın, aralığı hesaplayın ve sonra yeniden birleştirin mi? – Jesse

+0

@Jesse: Tanımladığınız şey, her anahtarın aynı olduğu (yani benzersiz olmayan) bir sözlük oluşturacaktır. Neden H'yi varsaymıyorsunuz, o zaman inotları bir SortedList'e koyunuz? –