linq命令由属性数组?

时间:2015-01-22 16:10:26

标签: c# linq-to-objects

拥有此代码

static void Main(string[] args)
{
    var test = new List<Tuple<string, int[]>>();

    test.Add(new Tuple<string, int[]>("a", new int[] { 1, 4, 7, 8 })); //item 1
    test.Add(new Tuple<string, int[]>("a", new int[] { 1, 2, 6, 5 })); //item 2
    test.Add(new Tuple<string, int[]>("b", new int[] { 1, 4, 7, 7 })); //item 3
    test.Add(new Tuple<string, int[]>("b", new int[] { 1, 2, 3, 4 })); //item 4
    test.Add(new Tuple<string, int[]>("a", new int[] { 1, 1, 4, 9 })); //item 5

    var result = test.OrderBy(x => x.Item1).ThenBy(x => x.Item2.OrderBy(y => y));
}

返回At least one object must implement IComparable.

不太确定怎么写那个linq所以我会得到这个结果

  1. 第5项
  2. 第2项
  3. 第1项
  4. 第4项
  5. 第3项

4 个答案:

答案 0 :(得分:2)

我疯狂猜测,因为你没有指定要求(为什么数组会出现在另一个数组之前),但是在收到评论之后,我会提供一个答案&#34;应该&#34;工作(我的想法并没有真正优化):

class ArrayComparer : IComparer<int[]>
{
  public int Compare(int[] x, int[] y)
  {
    for (var i = 0; i < x.Length && i < y.Length; i++)
    {
      if (x[i] > y[i])
        return 1;
      if (y[i] > x[i])
        return -1;
    }
    if (y.Length > x.Length)
      return -1;
    else if (y.Length < x.Length)
      return 1;
    return 0;
  }
}

然后:

var result = test.OrderBy(x => x.Item1)
        .ThenBy(x => x.Item2.OrderBy(y => y).ToArray(), new ArrayComparer());

我实际测试了它,这就是结果:

a -> 1,1,4,9 // item 5
a -> 1,2,6,5 // item 2
a -> 1,4,7,8 // item 1
b -> 1,2,3,4 // item 4
b -> 1,4,7,7 // item 3

答案 1 :(得分:2)

自定义IComparer<int[]>就是您想要的。这是我写它的方式。这将查看各个值,直到找到差异。如果在到达任一数组的末尾之前没有找到差异,那么它将根据数组的长度返回,并使用较短数组较小的度量。

public class ArrayComparer : IComparer<int[]>
{
    public int Compare(int[] x, int[] y)
    {
        for(int i = 0; i < x.Length && i < y.Length; i++)
        {
            if (x[i] != y[i])
                return x[i] - y[i];
        }

        return x.Length - y.Length;
    }
}

使用减法进行比较可以很好地指定IComparer的返回值。

要使用它,您只需编写

var result = test.OrderBy(x => x.Item1).ThenBy(x => x.Item2.OrderBy(y => y).ToArray(), new ArrayComparer());

答案 2 :(得分:0)

这似乎正在做我想要的事情

var result = test.OrderBy(x => x.Item1)
                 .ThenBy(x => string.Join(",", x.Item2.OrderBy(y => y)));

并且只能使用相同数量的数字......

答案 3 :(得分:0)

对于我的回答,我创建了一个自定义比较,它比较了Tuple类型和SequenceCompare,通常比较任何类型的数组。我相信这会很快。

这也可以很好地处理不同大小的数组 - 较长的数组可以“更大”。

static void Main(string[] args)
{
    var test = new List<Tuple<string, int[]>>();

    test.Add(new Tuple<string, int[]>("a", new int[] { 1, 4, 7, 8 })); //item 1
    test.Add(new Tuple<string, int[]>("a", new int[] { 1, 2, 6, 5 })); //item 2
    test.Add(new Tuple<string, int[]>("a", new int[] { 1, 2, 6  })); //item 2
    test.Add(new Tuple<string, int[]>("a", new int[] { 1, 2,  5 })); //item 2
    test.Add(new Tuple<string, int[]>("a", new int[] { 1,  6, 5 })); //item 2
    test.Add(new Tuple<string, int[]>("a", new int[] {  2, 6, 5 })); //item 2
    test.Add(new Tuple<string, int[]>("b", new int[] { 1, 2, 3, 4 })); //item 4
    test.Add(new Tuple<string, int[]>("a", new int[] { 1, 1, 4, 9 })); //item 5

    var result = test.OrderBy(x => x,new CustomComp()) ;

    result.Dump();
}


public class CustomComp : IComparer<Tuple<string, int[]>>
{
   public int Compare(Tuple<string, int[]> x,Tuple<string, int[]> y)
   {
     int strR = string.Compare(x.Item1,y.Item1);
     if (strR == 0)
       return x.Item2.SequenceCompare(y.Item2);
     else
     return strR;
   }
}

static class Compare
{
  public static int SequenceCompare<TSource>(this IEnumerable<TSource> x, IEnumerable<TSource> y)
  {
    return SequenceCompare(x,y,System.Collections.Generic.Comparer<TSource>.Default);
  }

  public static int SequenceCompare<TSource>(this IEnumerable<TSource> x, IEnumerable<TSource> y, IComparer<TSource> comparer)
  {
    if (x == null) throw new ArgumentNullException("x");
    if (y == null) throw new ArgumentNullException("y");

    using (IEnumerator<TSource> xe = x.GetEnumerator(), ye = y.GetEnumerator())
    {
      while (true)
      {
        bool next1 = xe.MoveNext();
        bool next2 = ye.MoveNext();

        // Are not of same length. longer one >
        if (next1 != next2)
        {
            if (next1 == true) return 1;
            return -1;
        }

        // Both finished -- equal
        if (!next1) return 0;

        int result = comparer.Compare(xe.Current, ye.Current);

        if (result != 0) return result;
      } 
    }
  }
}