2016-04-29 47 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