【问题标题】:How can I compare each element of a list with itself only once如何仅将列表的每个元素与其自身进行一次比较
【发布时间】:2012-08-06 01:42:38
【问题描述】:

不完全确定如何最好地表达这个问题。如何仅将列表的每个元素与同一列表的每个元素进行一次比较。

例如:

var textlist = ["a", "b", "c"];
var intersecting = from string a in textlist
                   from string b in textlist
                   where a != b && a.SomeCondition(b)
                   select new
                   {
                       object1 = a,
                       object2 = b
                   };

假设“a”用“b”为“SomeCondition”提供“True”,我希望最终结果是:

[["a, b"]]

而现在是:

[["a, b"], ["b, a"]]

这可以通过 Linq 查询实现吗?

【问题讨论】:

标签: c# linq linq-to-objects


【解决方案1】:

您可以使用值比较 - 即只处理 a > b 的对。您甚至可以将您的 a != b 替换为 a > b,因为这会暗示不等式:

var textlist = ["a", "b", "c"];
var intersecting = from string a in textlist
               from string b in textlist
               where a > b && (a.SomeCondition(b) || b.SomeCondition(a))
               select new
               {
                   object1 = a,
                   object2 = b
               };

【讨论】:

    【解决方案2】:

    一种方法是将每个元素与位于它之后的元素进行比较:

    string[] textlist = {"a", "b", "c"};
    var intersecting = from aIndex in Enumerable.Range(0, textlist.Count())
                       from b in textlist.Skip(aIndex + 1)
                       let a = textlist.ElementAt(aIndex)
                       where a != b && a.SomeCondition(b)
                       select new
                       {
                           object1 = a,
                           object2 = b
                       };
    

    注意:如果在枚举成本很高的 IEnumerable 上使用此解决方案以及大多数使用 LINQ 解决此问题的解决方案,效率将非常低。

    【讨论】:

    • 不是 100% 确定您拥有“最佳 (tm)”解决方案,但它正是我正在寻找的解决方案。除非我制作了比较运算符,否则其他人都不起作用,所以我将其标记为已回答。
    • @HotStuff 我很高兴这是你想要的!我相信对于急切评估的集合来说,这是一个非常有效的解决方案,因为与比较解决方案不同,它将每个元素与其他元素的一部分进行比较。此外,如果where a != b 只是为了防止将元素与其自身进行比较,则不需要它,因为b 将始终是a 之后的元素。如果您希望此解决方案对延迟评估的集合有效,您可以在使用它们之前将它们转换为急切集合。
    【解决方案3】:

    我通过添加 CompareTo 条件得到了您想要的结果:

    string[] textlist = new string[] {"a", "b", "c"};
    var intersecting =  from string a in textlist
                        from string b in textlist
                        where ((a != b) && (a.CompareTo(b) == -1)) // && a.SomeCondition(b)
                        select new { object1 = a, object2 = b }
                        ;
    
    intersecting.Dump("Result");
    

    这是结果的截图

    您可以删除多余的// 以取消注释您的条件。

    【讨论】:

      【解决方案4】:

      如果您不能在您的对象之间使用 > 或者您的集合可能包含重复项,这是另一种方法。它通过使用 SelectMany 和 Where 的重载来工作,该重载将索引传递给集合中的项目。我意识到它不是那么可读,但我认为它更健壮。

              string[] data = "A,A,B,C".Split(',');
              var query = data.SelectMany((x1, i1) => data.Where((x2, i2) => i2 > i1 && x1.SomeCondition(x2)).Select(x2 => new { object1 = x1, object2 = x2 }));
              foreach (var item in query) Console.WriteLine(item.object1 + "," + item.object2);
      

      【讨论】:

        猜你喜欢
        • 2013-06-06
        • 1970-01-01
        • 1970-01-01
        • 2015-04-02
        • 1970-01-01
        • 1970-01-01
        • 2020-03-04
        • 2019-01-19
        • 1970-01-01
        相关资源
        最近更新 更多