2016-04-29 73 views
2

有許多方法可以在列表中找到重複項,有什麼方法可以在列表中找到連續的重複項。在列表中查找連續的重複項

例如

List<string> stringList = new List<string>(); 
stringList.Add("Name1"); 
stringList.Add("Name2"); 
stringList.Add("Name1"); 

如果沒有發現任何但是

stringList.Add("Name1"); 
stringList.Add("Name1"); 
stringList.Add("Name2"); 

應該返回1項

這將返回重複。

var q = listString.GroupBy(x => x) 
     .Select(g => new { Value = g.Key, Count = g.Count() }) 
     .OrderByDescending(x => x.Count); 
+0

你想要什麼樣的結果?真/假結果,重​​復部分的列表? –

+2

顯示您在試圖解決此問題時編寫的代碼,以便我們可以查看出錯的位置。不要忘記告訴我們爲什麼它不起作用。並調試你的代碼。 –

+0

@ LasseV.Karlsen,如果我們可以得到哪個項目是重複的,並開始索引和發生次數。 – Pankaj

回答

1

爲什麼不的最後一個項目?事情是這樣的

public static partial class EnumerableExtensions { 
    // Simplest; IEquatable<T> for advanced version 
    public static IEnumerable<T> Continuous<T>(this IEnumerable<T> source) { 
    if (null == source) 
     throw new ArgumentNullException("source"); 

    T lastItem = default(T); 
    Boolean first = true; 

    foreach (var item in source) { 
     if (first) { 
     lastItem = item; 
     first = false; 
     } 
     else if (Object.Equals(item, lastItem)) 
     yield return item; 
     else 
     lastItem = item; 
    } 
    } 
} 

然後

List<string> stringList = new List<string>() { 
    "Name1", 
    "Name1", 
    "Name2", 
}; 

var contDups = stringList 
    .Continuous() 
    .ToList(); 
+0

由於運算符'=='不能應用於'T'和'T'類型的操作數,因此此邏輯在此行(項目== lastItem)上的編譯器錯誤除外。我把它改爲else if(item.Equals(lastItem)),它的作用就像一個魅力。 – Pankaj

+0

@Pankaj:我明白了,它應該是'Object.Equals(item,lastItem)' - safier版本(如果有'item','lastItem'爲'null')。看我的編輯。 –

1

您可以從定義意味着什麼項目是一個「連續重複的」開始:在位置

的項目i是連續重複,如果它與位置上的物品相同i-1

一個在先前位置來比較與另一值的值的方法是使用Zip與列表「偏移了」由一種元素:

var consecutiveDuplicates = list.Skip(1) 
    .Zip(list, (me, prior) => new {ThisItem = me, Prior = prior}) 
    .Where(p => p.ThisItem == p.Prior) 
    .Select(p => p.ThisItem) // Both sides are equal, pick either one 
    .ToList(); 

list.Skip(1).Zip(list,...)表達式列表與其自身結合的1的移位,所以你可以得到這個元素和其先前元素的N-1位置,其中先前的元素被定義。剩下的就是英語定義的簡單翻譯成LINQ語句

+0

感謝Upvoted,然而我正在將德米特里的回答標爲接受,因爲我首先嚐試了他的方法並且工作。 – Pankaj

2

下面是做這件事,返回重複的項目及其索引:

var duplicates = 
    stringList 
    .Select((x,i) => new {Item = x, Index = i}) 
    .Skip(1) //We start with the second item 
    .Where(y => y.Item == stringList[y.Index-1]) 
    .ToList(); 
+0

感謝Upvoted,但是我正在將德米特里的回答標爲接受,因爲我首先嚐試了他的方法並且工作。 – Pankaj

+1

@潘卡伊我認爲你應該標記最好的答案,而不是第一個答案。在工作時,德米特里代碼基本上與.Skip(1).Where((y,i)=> y == stringList [i])相同 –

2

既然你問:「如果我們能得到哪些產品複製和啓動索引和出現次數「,這是對特定需求的解決方案。

此輸出以下:

2 was repeated 2 times starting at index 1 
3 was repeated 3 times starting at index 4 
4 was repeated 4 times starting at index 8 

下面的代碼:

using System; 
using System.Collections.Generic; 

namespace Demo 
{ 
    class DupeInfo 
    { 
     public string Text; 
     public int Index; 
     public int Count; 
    } 

    static class Program 
    { 
     static void Main() 
     { 
      var test = new[] 
      { 
       "1", 
       "2", "2", 
       "A", 
       "3", "3", "3", 
       "B", 
       "4", "4", "4", "4", 
       "C", 
      }; 

      foreach (var dupeinfo in FindRepeats(test)) 
       Console.WriteLine($"{dupeinfo.Text} was repeated {dupeinfo.Count} times starting at index {dupeinfo.Index}"); 
     } 

     public static IEnumerable<DupeInfo> FindRepeats(IEnumerable<string> input) 
     { 
      int i = 0; 
      int j = 0; 
      int c = -1; 

      string prev = null; 

      foreach (var curr in input) 
      { 
       if (curr != prev) 
       { 
        if (c >= 0) 
         yield return new DupeInfo {Text = prev, Count = c + 2, Index = j}; 

        c = -1; 
        j = i; 
       } 
       else 
       { 
        ++c; 
       } 

       prev = curr; 
       ++i; 
      } 

      if (c >= 0) 
       yield return new DupeInfo {Text = prev, Count = c + 2, Index = j}; 
     } 
    } 
} 
+0

Spot On !,謝謝馬修 – Pankaj