2014-01-31 111 views
0

名單我有像這樣的列表:如何計算連續值與LINQ

var query = Enumerable.Range(0, 999).Select((n, index) => 
     { 
      if (index <= 333 || index >=777) 
       return 0; 
      else if (index <= 666) 
       return 1; 
      else 
       return 2; 
     }); 

所以,我能找到多少指標不斷有相同的價值?例如;

query[0]=query[1]=query[2]=query[3]... = 0, query[334] = 1, query[777]=query[778]... = 0.

首先334個指數有0,所以第一個答案是333同樣是在223個指數有0,所以第二個答案是223 ..

我怎樣才能找到這些和他們的指標?

在此先感謝。

+0

@SonerGönül,我回滾了編輯,因爲他們改變了問題的含義... –

+0

也許你應該保留修復語法和格式? – Magus

+0

@Magus我懶得把你的編輯合併成一個正確的。 –

回答

1

您可以通過一些關鍵創建擴展項目的連續分組:

public static IEnumerable<IGrouping<TKey, T>> GroupConsecutive<T, TKey>(
    this IEnumerable<T> source, Func<T, TKey> keySelector) 
{ 
    using (var iterator = source.GetEnumerator()) 
    { 
     if (!iterator.MoveNext()) 
      yield break;    
     else 
     { 
      List<T> list = new List<T>(); 
      var comparer = Comparer<TKey>.Default; 
      list.Add(iterator.Current); 
      TKey groupKey = keySelector(iterator.Current); 

      while (iterator.MoveNext()) 
      { 
       var key = keySelector(iterator.Current); 
       if (!list.Any() || comparer.Compare(groupKey, key) == 0) 
       { 
        list.Add(iterator.Current); 
        continue; 
       } 

       yield return new Group<TKey, T>(groupKey, list); 
       list = new List<T> { iterator.Current }; 
       groupKey = key; 
      } 

      if (list.Any()) 
       yield return new Group<TKey, T>(groupKey, list); 
     } 
    } 
} 

當然你可以返回IEnumerable<IList<T>>,但是這與你想要的組的概念有點不同,因爲你也想知道哪個值被用來對項目序列進行分組。不幸的是沒有公開的實施IGrouping<TKey, TElement>接口的,我們應該創造我們自己:

public class Group<TKey, TElement> : IGrouping<TKey, TElement> 
{ 
    private TKey _key; 
    private IEnumerable<TElement> _group; 

    public Group(TKey key, IEnumerable<TElement> group) 
    { 
     _key = key; 
     _group = group; 
    } 

    public TKey Key 
    { 
     get { return _key; } 
    } 

    public IEnumerator<TElement> GetEnumerator() 
    { 
     return _group.GetEnumerator(); 
    } 

    IEnumerator IEnumerable.GetEnumerator() 
    { 
     return GetEnumerator(); 
    } 
} 

現在用法很簡單:

var groups = query.GroupConsecutive(i => i) // produces groups 
        .Select(g => new { g.Key, Count = g.Count() }); // projection 

結果:

[ 
    { Key: 0, Count: 334 }, 
    { Key: 1, Count: 333 }, 
    { Key: 2, Count: 110 }, 
    { Key: 0, Count: 222 } 
] 
+0

我得到這樣的錯誤:擴展方法必須在非泛型靜態類中定義。我無法解決這個問題。 – 1teamsah

+0

@ team16sah完全按照錯誤說 - 在**非泛型靜態**類中定義擴展方法。你的班級不是靜態的,或者是通用的(或兩者都有) –

+0

非常感謝。現在,沒有錯誤。另外,我根據你的回答編輯了我的問題。如果有解決方案,你能幫我嗎? – 1teamsah

0
public static IEnumerable<int> GetContiguousCounts<T>(this IEnumerable<T> l, IEqualityComparer<T> cmp) 
    { 
     var last = default(T); 
     var count = 0; 
     foreach (var e in l) 
     { 
      if (count > 0 && !cmp.Equals(e, last)) 
      { 
       yield return count; 
       count = 0; 
      } 
      count++; 
      last = e; 
     } 
     if (count > 0) 
      yield return count; 
    } 

    public static IEnumerable<int> GetContiguousCounts<T>(this IEnumerable<T> l) 
    { 
     return GetContiguousCounts(l, EqualityComparer<T>.Default); 
    } 

    static void Main(string[] args) 
    { 
     var a = new[] { 1, 2, 2, 3, 3, 3 }; 
     var b = a.GetContiguousCounts(); 
     foreach (var x in b) 
      Console.WriteLine(x); 
    } 

對於簡單的測試情況下,輸出1,2,3,對於你的情況334,333,110,222(最後一個值是不是223,你在你的問題問,因爲你只需要999元素,而不是1000)。

1

here使用GroupConsecutive擴展方法你可以得到各組數:

query.GroupConsecutive((n1, n2) => n1 == n2) 
    .Select(g => new {Number = g.Key, Count = g.Count()}) 
0

嗯,怎麼樣這是我能想到的最有效的實現。

IEnuemrable<KeyValuePair<T, int>> RepeatCounter<T>(
     IEnumerable<T> source, 
     IEqualityComparer<T> comparer = null) 
{ 
    var e = source.GetEnumerator(); 
    if (!e.MoveNext()) 
    { 
     yield break; 
    } 

    comparer = comparer ?? EqualityComparer<T>.Default; 

    var last = e.Current; 
    var count = 1; 
    while (e.MoveNext()) 
    { 
     if (comparer.Equals(last, e.Current)) 
     { 
      count++; 
      continue; 
     } 

     yield return new KeyValuePair<T, int>(last, count); 
     last = e.Current; 
     count = 1; 
    } 

    yield return new KeyValuePair<T, int>(last, count); 
} 

枚舉序列只有一次,只在必要時分配變量。