【问题标题】:IEnumerable<IEnumerable<int>> - no duplicate IEnumerable<int>sIEnumerable<IEnumerable<int>> - 没有重复的 IEnumerable<int>s
【发布时间】:2011-01-16 22:00:28
【问题描述】:

我正在努力寻找解决这个问题的方法:

给定一个 IEnumerable> 我需要一个返回输入的方法/算法,但在多个具有相同元素的 IEnmerable 的情况下,每个巧合/组只返回一个。

例如

    IEnumerable<IEnumerable<int>> seqs = new[]
    { 
        new[]{2,3,4}, // #0 
        new[]{1,2,4}, // #1 - equals #3
        new[]{3,1,4}, // #2
        new[]{4,1,2}  // #3 - equals #1
    };

"foreach seq in seqs" .. 产生 {#0,#1,#2} 或 {#0,#2,#3}

我可以和..一起去吗?

.. 一些聪明的 IEqualityComparer

.. 一些我还没有想出的聪明的 LINQ 组合 - groupby, sequenceequal ..?

.. 一些 seq->HashSet 的东西

.. 什么不是。任何事情都会有帮助

我将能够通过良好的'n'old 编程来解决它,但总是很感激灵感。

【问题讨论】:

    标签: c# linq ienumerable


    【解决方案1】:

    这是 digEmAll 答案的稍微简单的版本:

    var result = seqs.Select(x => new HashSet<int>(x))
                     .Distinct(HashSet<int>.CreateSetComparer());
    

    鉴于您想将元素 视为 集,您应该以这种方式开始,IMO。

    当然,如果您想在返回的序列中保持顺序,这将无济于事,您只是不介意 返回的相等集合中的哪个...上面的代码将返回一个IEnumerable&lt;HashSet&lt;int&gt;&gt;,它将在每个序列中不再有任何排序。 (也不能保证 sets 的返回顺序,虽然如果不按照先见先返回的原则返回它们会很奇怪。)

    感觉这还不够,但如果您能提供更多关于您真正需要实现的目标的详细信息,那将更容易提供帮助。

    正如 cmets 中所述,这也将假定每个原始源数组 内 没有重复...或者至少,它们是不相关的,因此您很乐意对待 { 1 } 和 { 1, 1, 1, 1 } 相等。

    【讨论】:

    • +1 很好,但您应该警告 OP a) 不同频率的重复导致问题 b) 这会破坏每个数组中数字的顺序 c) 事实上这不是真的返回原始源序列的成员。
    • @Ani:我已经提到过破坏数组中数字的顺序,但现在我已经更明确地说明了这一点。将在每个数组中添加一些关于重复项的信息。
    • @Ani:不用担心 - 这是一个很好的关于数组中重复的问题:)
    • 这不是使用 ArrayEqualityComparer 的好时机吗?或类似的? :)
    • @Ani:在这种情况下不是——因为这取决于顺序。
    【解决方案2】:

    为作业使用正确的集合类型。你真正想要的是ISet&lt;IEnumerable&lt;int&gt;&gt; 和一个相等比较器,它将忽略IEnumerables 的顺序。

    【讨论】:

      【解决方案3】:

      已编辑:

      您可以通过构建自己的IEqualityComparer&lt;IEnumerable&lt;int&gt;&gt; 来获得所需的内容,例如:

      public class MyEqualityComparer : IEqualityComparer<IEnumerable<int>>
      {
          public bool Equals(IEnumerable<int> x, IEnumerable<int> y)
          {
              return x.OrderBy(el1 => el1).SequenceEqual(y.OrderBy(el2 => el2));
          }
      
          public int GetHashCode(IEnumerable<int> elements)
          {
              int hash = 0;
              foreach (var el in elements)
              {
                  hash = hash ^ el.GetHashCode();
              }
              return hash;
          }
      }
      

      用法:

      var values = seqs.Distinct(new MyEqualityComparer()).ToList();
      

      注意

      此解决方案与 Jon Skeet 给出的解决方案略有不同。
      他的回答将子列表视为集合,因此基本上像[1,2] 和[1,1,1,2,2] 这样的两个列表是相等的。

      此解决方案不,即:
      [1,2,1,1] 等于 [2,1,1,1] 但不等于 [2,2,1,1],因此基本上这两个列表必须包含相同的元素和相同的出现次数。

      【讨论】:

      • +1:从未听说过HashSet&lt;T&gt;.CreateSetComparer。但这并不完全正确。我认为最后一位应该是.Select(g =&gt; g.First()).ToList();
      • 我认为Where 子句不应该存在。
      • @Ani:是的,你是对的,实际上我误读了 OP 问题(我不知道为什么,但我认为他想排除多次出现的子列表...... O_O)。所以 Distinct 比 groupby-select first 更可取...
      • 鉴于我之前的解决方案部分错误,并且与 Jon Skeet 基本相同,我改变了方法;)
      • 感谢 digEmAll。我由此了解了我的 IEqualityComparer :)
      猜你喜欢
      • 1970-01-01
      • 2018-04-15
      • 1970-01-01
      • 1970-01-01
      • 2020-09-12
      • 2020-04-14
      • 2020-12-07
      • 1970-01-01
      • 2012-08-24
      相关资源
      最近更新 更多