【问题标题】:Linq OrderBy(Byte[]) valuesLinq OrderBy(Byte[]) 值
【发布时间】:2020-09-29 04:19:26
【问题描述】:
public class foo {
  int ID { get; set; }
  byte[] sort { get; set; }
}

public class barMaster {
    public void FooSource() {
        return List<foo> FromDataSource;
    }
    public void display() {
        List<foo> sortedFoo = FooSource().OrderBy(f => f.sort);
        UIElement = sortedFoo;
    }

我有一组包含我想要 OrderBy 的 byte[] 属性的对象,但是 OrderBy(byte[]) 会引发错误:

System.ArgumentException: At least one object must implement IComparable.

我可以对 OrderBy byte[] 值做什么?

【问题讨论】:

  • 你必须实现接口ICompareble并为订单创建你自己的函数
  • 那么如果f1f1.sort == { 3, 201, 25, }f2f2.sort == { 3, 29, 7, 222, 0, } 哪个更大,f1f2,为什么?
  • 就我的目的而言,f1 将被认为大于 f2,因为 201 > 29。我可以理解为什么从“正确行为”的角度来看,这将是难以融入框架的行为。

标签: c# linq


【解决方案1】:

作为you've indicated that the arrays are of variable length(因为它是SQL Server 层次结构ID),您绝对需要创建自定义IComparer&lt;byte[]&gt; 实现。

逻辑很简单:

  • 逐字节比较每个数组的第一个n 字节,其中n 是两个数组中较小的一个的字节数。当检测到任何字节之间存在差异时,返回不同字节的比较结果。
  • 如果第一个 n 字节相等,则返回两个数组长度的比较。

这样,给定一组数据如下:

00 01 02
00 01
01

排序后,您将得到的结果是:

00 01
00 01 02
01

也就是说,这就是您的 IComparer&lt;byte[]&gt; 实现的样子:

// I could be wrong in that this is called natural order.
class NaturalOrderByteArrayComparer : IComparer<byte[]>
{
    public int Compare(byte[] x, byte[] y)
    {
        // Shortcuts: If both are null, they are the same.
        if (x == null && y == null) return 0;

        // If one is null and the other isn't, then the
        // one that is null is "lesser".
        if (x == null && y != null) return -1;
        if (x != null && y == null) return 1;

        // Both arrays are non-null.  Find the shorter
        // of the two lengths.
        int bytesToCompare = Math.Min(x.Length, y.Length);

        // Compare the bytes.
        for (int index = 0; index < bytesToCompare; ++index)
        {
            // The x and y bytes.
            byte xByte = x[index];
            byte yByte = y[index];

            // Compare result.
            int compareResult = Comparer<byte>.Default.Compare(xByte, yByte);

            // If not the same, then return the result of the
            // comparison of the bytes, as they were the same
            // up until now.
            if (compareResult != 0) return compareResult;

            // They are the same, continue.
        }

        // The first n bytes are the same.  Compare lengths.
        // If the lengths are the same, the arrays
        // are the same.
        if (x.Length == y.Length) return 0;

        // Compare lengths.
        return x.Length < y.Length ? -1 : 1;
    }
}

顺便说一句,如果您的字节数组保证长度相同,作为替代方案,您可以动态创建 order by 子句,按第一个元素排序,然后是第二个元素,依此类推,如下所示:

static IEnumerable<foo> OrderBySortField(this IEnumerable<foo> items, 
    int sortLength)
{
    // Validate parameters.
    if (items == null) throw new ArgumentNullException("items");
    if (sortLength < 0) throw 
        new ArgumentOutOfRangeException("sortLength", sortLength,
            "The sortLength parameter must be a non-negative value.");

    // Shortcut, if sortLength is zero, return the sequence, as-is.
    if (sortLength == 0) return items;

    // The ordered enumerable.
    IOrderedEnumerable<foo> ordered = items.OrderBy(i => i.sort[0]);

    // Cycle from the second index on.
    for (int index = 1; index < sortLength; index++)
    {
        // Copy the index.
        int indexCopy = index;

        // Sort by the next item in the array.
        ordered = ordered.ThenBy(i => i.sort[indexCopy]);
    }

    // Return the ordered enumerable.
    return ordered;
}

然后你可以简单地这样称呼它:

// You have to supply the length of the array you're sorting on.
List<foo> sortedFoo = FooSource().
    OrderBySortField(sortLength).ToList();

【讨论】:

  • 数组的长度不是固定的,因为它是来自 SQL Server 的层次结构的表示。
  • @StormRider01 我已更新答案以解决您的特定实例。我已经离开了之前的解决方案,但是首先显示的是您处理可变长度数组的解决方案。
【解决方案2】:

您不能直接按byte[] 排序,因为数组不实现IComparable。您需要按第一个字节排序(即:OrderBy(f =&gt; f.sort[0]) 或其他适当的内容),或者编写自己的IComparer&lt;byte[]&gt; 并在OrderBy 的适当重载中使用它。

【讨论】:

    【解决方案3】:

    不幸的是,据我所知,您无法按字节数组排序。

    你可以做的是让你的 foo 类实现 IComparable。然后在覆盖的 compareTo 方法中,在调用中根据需要编写字节数组的比较。然后,您可以使用简单的排序来替换 Order By:

    FooSource().Sort();   
    

    【讨论】:

      【解决方案4】:

      我知道,这是一个老问题,但在特定情况下,当字节数组包含一个数字(例如 IP 地址)时,BitConverter 类可用:

      OrderBy(d => BitConverter.ToInt32(d.bytearray,0))
      

      来源:https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/types/how-to-convert-a-byte-array-to-an-int

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-09-11
        • 1970-01-01
        • 1970-01-01
        • 2012-07-25
        • 2020-06-10
        • 2011-11-21
        相关资源
        最近更新 更多