在LINQ中高效的列表自比较

本文关键字:列表 比较 高效 LINQ | 更新日期: 2023-09-27 18:14:45

这可能与这个问题非常相似,但我想知道c#和LINQ中最有效的方法来比较同一列表中的元素列表。

例如,在伪代码中我想这样做:

foreach(i in list)    
    foreach(j in list.Except(i))    
        Compare(j,i)

我知道Except接受一个可枚举对象而不是单个对象,这可能不是最好的主意,但它应该说明我的意图。

任何想法?

更新:

我想这个问题有点模糊。目标是在列表上迭代两次(使用LINQ),同时跳过对(i, i);无论Compare(i,j)实际做什么都与我的问题无关。

有两种情况,一种是(i,j) == (j,i)(i,j) != (j,i)。对于前者,George Duckett的跳跃式解决方案可以解决问题,但对于后者呢?这就是我最初使用Except的地方,这样(i,j)(j,i)都将被求值。

那么澄清一下,除了list.Except(Enumerable.Repeat(i,1))之外,有没有更好的方法来跳过列表中的元素呢?

在LINQ中高效的列表自比较

这将给你所有的配对,假设配对的顺序无关(Compare(i, j) == Compare(j, i)):

var test = from i in list
           from j in list.SkipWhile(j => j != i)
           where i != j // Remove the self-comparison if you want to
           select Compare(i, j);

我不知道你是否对LINQ有需求,但我很可能会这样写这段代码,这样当我从现在起3周后回顾代码时,我一眼就知道是怎么回事。

for(var i = 0; i < list.Count; ++i)
{
    var item = list[i];
    for(var j = i+1; j < list.Count; ++j)
    {
        Compare(item, list[j]);
    }
}

如果你还想使用LINQ,你可以这样重写:

for(var i = 0; i < list.Count; ++i)
{
    var item = list[i];
    foreach(var j in list.Skip(i+1))
    {
        Compare(item, j);
    }
}

您的需求需要更多的说明,但这可以帮助您:

List<int> list = new List<int>() { 1, 2, 3, 4 };
var result = list.Aggregate((p, q) => p.CompareTo(q) > 0 ? p : q);//Return 4

你的问题有点模糊,你想用比较的结果做什么,但这里有一个想法:

public static IEnumerable<TResult> Compare<T, TResult>(this IEnumerable<T> source,  Func<T, T, TResult> func)
{
    int i = 0;
    foreach (T item1 in source)
    {
        foreach (T item2 in source.Skip(i))
            yield return func(item1, item2);
        i++;
    }
}

然后你可以对比较的结果做任何你想做的事情。例如,使用这些List对象:

List<string> list = new List<string> { "test", "hello", "foo", "bar" };

你可以这样做:

var compared = list.Compare((item1, item2) => item1.Equals(item2));
//compared will be IEnumerable<bool> in this case

或:

var compared = list.Compare((item1, item2) => new { item1, item2 });
//to get an enumerator of all the different comparisons of the 2 lists