有没有办法在不必实现IComparer <t>的情况下使用自定义OrderBy或Min?

时间:2017-03-04 19:58:21

标签: c# .net linq

我想写的是

        return possibilities.OrderBy((x, y) =>
            {
                // returns true or false depending on whether x is 
                // lexographically smaller than y, e.g. x={1,2,3} 
                // is lexographically smaller than y={1,3,2}
                for(int i = 0; i < x.Length; ++i)
                {
                    if(x[i] < y[i])
                        return true;
                    else if(x[i] > y[i])
                        return false;
                }
                return true;
            })
            .First();

其中possibilities的类型为IEnumerable<int[]>。但是,我很惊讶这个语法无效,而且我可以通过Googling找到的所有东西都表明我必须编写一堆额外的代码来实现IComparer<int[]>。真?

3 个答案:

答案 0 :(得分:5)

Comparer<T>.Create(Comparison<T>)可以在.NET 4.5或更高版本中使用:

IEnumerable<int[]> a = new[] { new []{ 1, 2 }, new[] { 3, 4 } };

int[] min = a.OrderBy(x => x, Comparer<int[]>.Create((x, y) => {
    for (int z, i = 0; i < x.Length; i++)
        if ((z = x[i] - y[i]) != 0) return z;
    return 0;
})).FirstOrDefault();

但不需要找到最低限度:

int[] min = a.Aggregate((x, y) => {
    for (int i = 0; i < x.Length; ++i) {
        if (x[i] < y[i]) return x;
        if (x[i] > y[i]) return y;
    }
    return x;
});

答案 1 :(得分:1)

您可以实现并重用接受比较委托的比较器,如下所示:

public class DynamicComparer<T> : IComparer<T> {
    private readonly Func<T, T, int> _comparer;
    public DynamicComparer(Func<T, T, int> comparer) {
        _comparer = comparer;
    }
    public int Compare(T x, T y) {
        return _comparer(x, y);
    }
}

然后在您需要的所有地方使用它:

possibilities.OrderBy(c => c, new DynamicComparer<int[]>((x, y) =>
{
    for (int i = 0; i < x.Length; ++i)
    {
        if (x[i] < y[i])
            return -1;
        else if (x[i] > y[i])
            return 1;
    }
    return 0;
}));

请注意,正如另一个答案所示,.NET 4.5中已存在这样的比较器,可以使用Comparer<int[]>.Create创建。如果您使用的是.NET 4.5,则无需像这样创建自己的比较器。

您甚至可以进一步实施自己的OrderBy扩展方法:

public static class Extensions {
    public static IOrderedEnumerable<T> OrderBy<T>(this IEnumerable<T> items, Func<T, T, int> comparer) {
        return items.OrderBy(c => c, new DynamicComparer<T>(comparer));
    }
}

然后就像你想要的那样:

possibilities.OrderBy((x, y) =>
{
    for (int i = 0; i < x.Length; ++i)
    {
      if (x[i] < y[i])
          return -1;
      else if (x[i] > y[i])
          return 1;
      }
      return 0;
 });

答案 2 :(得分:-2)

我认为一个简单的方法就是

return possibilities.OrderBy(x => String.Join(".",x.ToString.PadLeft(10,'0'))).First();

原因。是分隔段,垫的长度为10的原因是0s是max int是20亿,所以10个最大字符。