2017-10-15 79 views
0

的可能範圍,我的ID(int)像獲取INT收集

[1,2,3,5,7,8,11,13,14..] 

列表是有一個快速/智能方式(LINQ?)來獲取所有的id,或者如果可能的話,範圍是多少? 結果應該像[1-3, 5, 7-8, 11, 13-14]

當然,很容易循環和計算int值來獲得結果,但我確定必須有一個更簡單的方法來做到這一點。

+0

什麼是產生一系列的邏輯是什麼?爲什麼不是1-5,3-8等? – Sajeetharan

+0

_is有一個快速/智能的方式(linq?)_ - 如果通過「快」你的意思是執行速度,那麼「foreach」將總是更快然後LINQ – Fabio

回答

0

老學校的方式與一個單一的循環。

try 
{ 
    List<int> i = new List<int>() { 1, 2, 3, 5, 7, 8, 11, 13, 14 }; 
    int istart = i[0]; 
    bool flag = false; 
    // Use StringBuilder 
    for(int index = 0;index<i.Count-1;index++) 
    { 
     if ((i[index] + 1) == i[index + 1]) 
     { 
       flag = true; 
       continue; 
     } 
     else 
     { 
       if (!flag) 
        Console.Write(istart); 
       else 
        Console.Write(istart + "-" + i[index]); 

       Console.Write(","); 

       flag = false; 
       istart = i[index + 1]; 
      } 
     } 
     if (istart + 1 == i[i.Count - 1]) 
      Console.Write(istart + "-" + i[i.Count - 1]); 
     else 
      Console.WriteLine(istart); 
} 
catch(Exception ex) 
{ 
     Console.WriteLine(ex.Message); 
} 
Console.WriteLine(); 
Console.WriteLine("Done"); 
Console.Read(); 

輸入List<int> i = new List<int>() { 1, 2, 3, 5, 7, 8, 11, 13, 14 };

enter image description here

輸入List<int> i = new List<int>() { 1, 2, 3, 4, 5, 7, 8, 11, 13, 13 };

enter image description here

輸入List<int> i = new List<int>() { 1, 4, 5, 7, 8, 9, 2, 13, 15, 17 };

enter image description here

0

有一個LINQ的方式來做到這一點(如果號碼不重複),但我不知道這是否是簡單:

int last = -1; 
int rank = 0; 
IEnumerable<string> grouped = arr 
    .GroupBy(i => 
    { 
     rank += i - last - 1; 
     last = i; 
     return rank; 
    }) 
    .Select(g => g.Count() == 1 ? g.First().ToString() 
       : g.First().ToString() + "-" + g.Last().ToString()); 

似乎相當複雜對我來說,比需要更多的資源密集型並不靈活。 Linq對於很多案例來說都很棒,但有時候它並不適合。簡單的循環有時是最好的,你可以得到:

IEnumerable<string> Group(IEnumerable<int> sortedArr) 
{ 
    using (var en = sortedArr.GetEnumerator()) 
    { 
     if (!en.MoveNext()) 
     { 
      yield break; 
     } 
     int first = en.Current; 
     int last = first; 
     int count = 1; 

     while (true) 
     { 
      bool end; 
      if ((end = !en.MoveNext()) || en.Current - last > 1) 
      { 
       if (count == 1) 
       { 
        yield return first.ToString(); 
       } 
       //else if (count == 2) 
       //{ 
       // yield return first.ToString(); 
       // yield return last.ToString(); 
       //} 
       else 
       { 
        yield return first.ToString() + "-" + last.ToString(); 
       } 
       if (end) { yield break; } 
       first = en.Current; 
       count = 1; 
      } 
      else 
      { 
       ++count; 
      } 
      last = en.Current; 
     } 
    } 
} 

基準

讓我們衡量如何(中)高效LINQ實際上是這裏10M陣列上:

simple loop: 328MB, 1.2sec 
     my linq: 790MB, 2.7sec 
Fredous linq: 1100MB, 7days (estimated) 

的代碼:

int size = 10000000; 
int[] arr = new int[size]; 
Random rnd = new Random(1); 

arr[0] = 0; 
for(int i = 1; i < size; ++i) 
{ 
    if (rnd.Next(100) < 25) 
    { 
     arr[i] = arr[i - 1] + 2; 
    } 
    else 
    { 
     arr[i] = arr[i - 1] + 1; 
    } 
}   

System.Diagnostics.Stopwatch st = new System.Diagnostics.Stopwatch(); 
st.Start(); 
var res = Group(arr).ToList(); 
st.Stop(); 

MessageBox.Show(st.ElapsedMilliseconds.ToString()); 
MessageBox.Show(res.Sum(s => s.Length).ToString());// to be sure the work is done 
+0

你應該把實際的基準代碼也放在答案;-) – Fredou

+0

@Fredou好吧,加 –

+0

我補充了一點聲明在我的答案;-) – Fredou

1

免責聲明這是大名單上的速度很慢,你應該做一個獨特的太

這應該做的伎倆

static void Main(string[] args) 
    { 
     //a list with a possible of duplicate 
     var theList = (new int[] { 1, 2, 3, 5, 7, 8, 11, 13, 14, 13 }).OrderBy(x => x).ToList(); 

     var step1 = theList.Select((a, b) => theList.Skip(b).TakeWhile((x, y) => a == x || theList[b + y] - 1 == theList[b + y - 1])); 

     var step2 = step1.GroupBy(x => x.Last()) 
         .Select(x => x.SelectMany(y => y).Distinct()) 
         .Select(x => x.Count() > 1 ? string.Format("{0}-{1}", x.First(), x.Last()) : x.First().ToString()); 


     var result = string.Format("[{0}]", string.Join(", ", step2)); 

    } 
0

考慮一個有序列表和唯一的ID,我認爲最簡單的方法是使用經典

List<int> ids = new List<int>() { 1, 2, 3, 5, 7, 8, 11, 13, 14 }; 
       int i = 0; 
       bool isrange; 

       for(i=0;i<ids.Count;i++) 
       { 
        isrange = false; 
        Console.Write(ids[i]); 

        while (i < ids.Count-1 && ids[i + 1] == ids[i] + 1) 
        { 
         i++; 
         isrange = true; 
        } 

        if (isrange) 
         Console.Write("-" + ids[i]); 

        if (!(i + 1 == ids.Count)) 
         Console.Write(","); 
       }