【问题标题】:Finding duplicate in a list of a list of integers在整数列表的列表中查找重复项
【发布时间】:2017-05-17 11:06:55
【问题描述】:

在整数列表中查找重复项的最佳方法是什么(无论它们在什么位置)?我不需要代码只是解决这个问题的最佳方法(在 C# 中)。

例如:

List<List<int>> TestData = new List<List<int>>
{
     new List<int> { 1, 2, 3 },
     new List<int> { 2, 1, 3 },
     new List<int> { 6, 8, 3, 45,48 },
     new List<int> { 9, 2, 4 },
     new List<int> { 9, 2, 4, 15 },
};

这个想法是这会返回

   Count | Set
----------------
   2x    | 1,2,3
   1x    | 6, 8, 3, 45, 48
   1x    | 9,2,4
   1x    | 9, 2, 4, 15

我一直在为这个看似非常简单的问题而烦恼,但由于某种原因我无法弄清楚。希望有人能够提供帮助,就像我说的代码不是必需的,但非常感谢。

【问题讨论】:

  • 定义最佳方式 - 最短代码,最佳性能(以及哪一个 - 内存/速度)?
  • 您可以使用字典或哈希表来实现这一点
  • 也许你应该试试Linq...TestData.Select(L =&gt; L.Sort()).GroupBy(x =&gt; x) => 返回值按列表分组
  • 如果列表不包含重复项,@Jodrell 解决方案是最好的。如果您提供一些反馈,那就太好了。
  • @IvanStoev 同意,​​如果列表不应该被视为集合而是序列,那么相等规则需要详细说明。

标签: c# list jagged-arrays


【解决方案1】:

嗯,首先你要将列表转换为集合,

var testSets = testData.Select(s => new HashSet<int>(s));

然后您可以将集合分组为相等。

var groupedSets = testSets.GroupBy(s => s, HashSet<int>.CreateSetComparer());

这是fully working example

using System;
using System.Collections.Generic;
using System.Linq;

public class Test
{
    public static void Main()
    {
        var testData = new List<List<int>>
        {
             new List<int> { 1, 2, 3 },
             new List<int> { 2, 1, 3 },
             new List<int> { 6, 8, 3, 45, 48 },
             new List<int> { 9, 2, 4 },
             new List<int> { 9, 2, 4, 15 }
        };

        var testSets = testData.Select(s => new HashSet<int>(s));

        var groupedSets = testSets.GroupBy(s => s, HashSet<int>.CreateSetComparer());

        foreach(var g in groupedSets)
        {
            var setString = String.Join(", ", g.Key);
            Console.WriteLine($" {g.Count()} | {setString}");
        }
    }
}

【讨论】:

  • 感谢优雅的解决方案,但唯一的问题是我还需要比较集合的长度。所以像 {1,2,3 }, {3, 1, 2} 和​​ { 1,2,3,4} 这样的列表应该返回:2x 1,2,3 和 1x 1,2,3,4
  • @John 这就是将要发生的事情。 {1, 2, 3} 等于 {3, 1, 2} 但不等于 {1, 2, 3, 4}。您可以点击链接进行演示,
【解决方案2】:

您应该使用适当的数据结构来执行您的要求。在这种情况下,你有一个集合到整数的字典:

IDictionary<ISet<int>, int>

如果您不想使用 LINQ(这可能是最佳实践,请参阅其他答案),您可以按如下方式构建它:

var result = new Dictionary<HashSet<int>, int>();

foreach (var i in TestData)
{
    var key = new HashSet<int>(i);

    int count;

    result.TryGetValue(key, out count);
    result[id] = count + 1;
}

【讨论】:

    【解决方案3】:

    尝试以下:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    
    namespace ConsoleApplication1
    {
        class Program
        {
            static void Main(string[] args)
            {
                List<List<int>> TestData = new List<List<int>>
                {
                     new List<int> { 1, 2, 3 },
                     new List<int> { 2, 1, 3 },
                     new List<int> { 6, 8, 3 },
                     new List<int> { 9, 2, 4 },
                };
    
                var values = TestData.SelectMany(x => x).GroupBy(x => x).ToList();
                var counts = values.Select(x => new { value = x.Key, times = x.Count() }).ToList();
    
                var times = counts.GroupBy(x => x.times).Select(x => new { key = x.Key, values = x.Select(y => y.value).ToList() }).OrderBy(x => x.key).ToList();
    
            }
    
        }
    
    }
    

    【讨论】:

      【解决方案4】:
       The answer of @Jodrell is very elegant (for me is the best), but only say depends of what you want the answer is correct
      
          For the nex data
                      var testData = new List<List<int>>
                  {
                       new List<int> { 1, 2, 3 },
                       new List<int> { 1, 2, 3 },
                       new List<int> { 1, 2, 3, 3 },
                  }
      
          The result is going to be:
      
          Count | Set
      
          3x |  1,2,3
      
          And not the next:
      
          Count | Set
      
          2x    | 1,2,3
      
             1x    | 1,2,3,3
      
          So depends of your question...
      
      
          Ok, so, with the last one this is my code, is not fancy and you can improve a lot of things
      
          enter code here
      
      
       using System;
          using System.Collections.Generic;
          using System.Linq;
          using System.Text;
          using System.Threading.Tasks;
      
          namespace TestListInt
          {
              class Program
              {
                  public class WrapperListInt
                  {
                      public List<int> list;
                      public WrapperListInt(List<int> list)
                      {
                          this.list = list;
                      }
      
                      public override int GetHashCode()
                      {
                          return 0;
                      }
                      public override bool Equals(object obj)
                      {
                          if (this == obj) return true;
                          WrapperListInt o = obj as WrapperListInt;
                          if (this.list.Count != o.list.Count) return false;
      
                          for (int i = 0; i < this.list.Count; i++)
                          {
                              if (this.list[i] != o.list[i]) { return false; }
                          }
      
                          return true;
                      }
                  }
                  public Program() {
                      var testData = new List<List<int>>
                  {
                       new List<int> { 1, 2, 3 },
                       new List<int> { 1, 3, 2 },
                       new List<int> { 1, 2, 3, 3 },
                       new List<int> { 6, 8, 3, 45,48 },
                       new List<int> { 9, 2, 15, 4 },
                       new List<int> { 9, 2, 4},
                       new List<int> { 9, 2, 4, 15 }
                  };
      
                      //Order every list
                      foreach (var td in testData)
                      {
                          td.Sort();
                      }
      
      
                      Dictionary<WrapperListInt, int> dic = new Dictionary<WrapperListInt, int>();
                      foreach (var listInt in testData)
                      {
                          WrapperListInt aux = new WrapperListInt(listInt);
                          int countList;
                          if (dic.TryGetValue(aux, out countList))
                          {
                              dic[aux]++;
                          }
                          else
                          {
                              dic.Add(aux, 1);
                          }
                      }
      
                      foreach (var d in dic)
                      {
                          var setString = String.Join(", ", d.Key.list);
                          Console.WriteLine($" {d.Value} | {setString}");
                      }
                  }
                  static void Main(string[] args)
                  {
                      new Program();
                  }
              }
          }
      

      【讨论】:

      • 我是说最后一个
      • @John 我放了代码,但我把格式弄乱了,对不起。
      猜你喜欢
      • 2016-11-18
      • 2013-11-17
      • 1970-01-01
      • 2013-02-21
      • 2015-08-31
      • 1970-01-01
      • 2015-08-31
      • 1970-01-01
      相关资源
      最近更新 更多