2013-06-28 76 views
0

給定以下數字(表示星期幾):1,2,3,4,5,6,7用LINQ挑戰管理範圍

下面是一些組合的實施例和它們的期望輸出:

  • 1,2,3,5,6,7 - >1-3,5-7
  • 1,3,5,7 - >1,3,5,7
  • 1,2,5,6 - >1,2,5,6
  • 1,2,3,6,7 - >1-3,6,7

這個想法是,連續3天或更多天成爲一個範圍,而單獨或不跟隨的日子單獨呈現(或者更好地使範圍從2開始)。

我不知道從哪裏開始,我應該寫一個複雜的if ed函數,或者這可以通過LINQ函數之一完成?
有沒有多汁的建議?

我用數字來簡化範圍的想法,但在我的代碼我有一個標記的枚舉聲明如下:

[Flags] 
public enum DaysOfWeek 
{ 
    Sunday = 0x1, 
    Monday = 0x2, 
    Tuesday = 0x4, 
    Wednesday = 0x8, 
    Thursday = 0x10, 
    Friday = 0x20, 
    Saturday = 0x40 
} 

我有一個實體OpeningTimes與現場DaysOfWeek,告訴什麼天一週此實體的小時範圍(在另一個屬性中定義)適用於。

所以得到我用上面的(真正得到的數字我會使用索引+ 1加Select):

var days = Enum.GetValues(typeof(DaysOfWeek)) 
      .Cast<DaysOfWeek>() 
      .Where(dow => Model.DaysOfWeek.HasFlag(dow)); 

我認爲這個想法是一個範圍內,首先刪除號碼。

我相信我正在尋找一個接收前一個值的聚合函數,並且可以返回另一個值類型,所以我可以創建一個函數,如果當前值-1等於prev。值,我等待下一個值,直到範圍不連續(或者如果元素代表自己),這是我產生時返回最後一個批量作爲匿名對象,並開始在新的工作。

然後我會作出這樣的表示if (item.First != item.Last) string.Join("-", item.First, Item.Last);

回答

1

有趣的問題。我決定了可讀性有一個表示範圍的一類:

class NumberRange 
{ 
    public int Start { get; set;} 
    public int End { get; set;} 
    public override string ToString() 
    { 
     return Start == End ? Start.ToString() : String.Format("{0}-{1}",Start,End); 
    } 
} 

和擴展方法把有序整數的IEnumerable爲範圍的IEnumerable:

public static IEnumerable<NumberRange> ToRanges(this IEnumerable<int> numbers) 
{ 
    NumberRange currentRange = null; 
    foreach(var number in numbers) 
    { 
     if (currentRange == null) 
      currentRange = new NumberRange() { Start = number, End = number }; 
     else if (number == currentRange.End + 1) 
      currentRange.End = number; 
     else 
     { 
      yield return currentRange; 
      currentRange = new NumberRange { Start = number, End = number }; 
     } 
    } 
    if (currentRange != null) 
    { 
     yield return currentRange; 
    } 
} 

有了這樣的地方,你可以得到的範圍和格式,但你想要的:

String.Join(",", 
    new int[] { 1,2,3,5,7,8,9,11 } 
     .ToRanges() 
     .Select(r => r.ToString())) 
1

這裏格式化函數是什麼,我想:

void Main() 
{ 
    Console.WriteLine(AggregateString(new int[]{1,2,3,5,6,7})); //1-3,5-7 
    Console.WriteLine(AggregateString(new int[]{1,3,5,7}));  //1,3,5,7 
    Console.WriteLine(AggregateString(new int[]{1,2,5,6}));  //1,2,5,6 
    Console.WriteLine(AggregateString(new int[]{1,2,3,6,7 })); //1-3,6,7 
} 


string AggregateString(int[] ary) 
{ 
    List<List<int>> result=new List<List<int>>(); 
    ary.Aggregate((m,n)=> 
     { 
      if(m == n-1) 
      { 
      if(result.LastOrDefault()!=null && result.LastOrDefault().Last() ==m) 
       result.Last().Add(n); 
      else 
       result.Add(new List<int>{m,n}); 
      } 
      else 
      { 
       if(result.LastOrDefault()==null) 
        result.Add(new List<int>{m,n}); 
       else result.Add(new List<int>{n}); 
      } 
      return n; 
     }); 
    return string.Join(",", result.Select(s=>s.Count()>2? 
        string.Join("-",new string[]{s.First().ToString(),s.Last().ToString()}) : 
        string.Join(",",s.Select(x=>x.ToString()).ToArray())).ToArray()); 
} 
+0

你也可以使用鋸齒陣列 – Shimmy

+1

鋸齒陣列是不好的linq。所以我更喜歡List。 :) –

+0

稍後我會調整你的代碼,但我認爲這是我要使用的。 – Shimmy

1

以下是一張就可以了。 (不幸的是,我無法防止複製一個部分:

static IEnumerable<string> GetRange(IEnumerable<int> range) 
{ 
    using(IEnumerator<int> iter = range.GetEnumerator()) 
    if(iter.MoveNext()) 
    { 
     int last = iter.Current; 
     int start = iter.Current; 
     while(iter.MoveNext()) 
     { 
      int curr = iter.Current; 
      if (curr == last+1) 
      { 
       last = curr; 
       continue; 
      } 
      // found gap 
      if (start == last) // one isolated value 
      { 
       yield return start.ToString(); 
      } 
      else if (last - start == 1) // two in a row. 
      { 
       yield return start.ToString(); 
       yield return last.ToString(); 
      } 
      else 
      { 
       yield return string.Format("{0}-{1}", start,last); 
      } 
      start = curr; 
      last = curr;    
     } 

     if (start == last) // one isolated value 
     { 
      yield return start.ToString(); 
     } 
     else if (last - start == 1) // two in a row. 
     { 
      yield return start.ToString(); 
      yield return last.ToString(); 
     } 
     else 
     { 
      yield return string.Format("{0}-{1}", start,last); 
     } 
    } 
}