动态LINQ查询字符串,用于索引IEnumerableObjects,以实现高效的多维数组排序



我一直在试图找出最有效和灵活的方式来排序多维数组的多列,其中排序条件不知道,直到运行时

起初,我使用三种不同的方法来处理数据表和排序:选择、DataView。排序,并在数据表上使用LINQ。前两个方法允许您通过构建排序字符串在运行时动态指定排序条件。

经过一番研究,我发现动态LINQ允许你通过一个类似于传递给DataTable的字符串来执行OrderBy, ThenBy等操作。选择或DataView。排序:http://dynamiclinq.azurewebsites.net/GettingStartedhttps://www.nuget.org/packages/System.Linq.Dynamic/

也关于并行LINQ,这样你就可以在你的排序中使用多个内核(不兼容数据表,因为它们不是线程安全的):https://msdn.microsoft.com/en-us/library/dd460688(v=vs.110).aspx

因此,我认为我可以基于运行时提供的多个排序条件以一种比使用DataTable更有效的方法执行多维数组排序。

我想出了下面的代码。但是,如果我将数据包装在自定义对象中,我只能获得动态LINQ和并行LINQ工作,因为我无法弄清楚如何为列表或锯齿数组构建动态LINQ查询字符串。

有没有人知道我需要做什么改变我的查询字符串动态LINQ得到我的排序工作?我在下面的代码中试图纠正的字符串是"0 ASC, 2 DESC, 1 ASC"。

请注意,当我将数据包装在一个名为Row的自定义对象中时,我可以很好地构建DLINQ字符串并使其正确排序。但是,如果能摆脱由此产生的额外开销就好了。

下面的代码按3列对测试数组进行排序。我使用混合的测试用例来使用LINQ和动态LINQ的各种方法

using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Dynamic;
namespace MultiDimensionalArraySorting
{
    class Program
    {
    static void Main(string[] args)
    {
        var testArray = new IComparable[,]{
            {1, "a", new DateTime(2000, 1, 1)},
            {2, "a", new DateTime(2000, 1, 2)},
            {1, "c", new DateTime(2000, 1, 1)},
            {5, "a", new DateTime(2000, 1, 1)},
            {2, "a", new DateTime(2000, 1, 1)},
        };
        int numRows = testArray.GetLength(0);
        int numCols = testArray.GetLength(1);
        var listOfRows = TwoDimensionalArrayToListOfRows(testArray);
        var aSortedUsingLinqOnListOfRows = new IComparable[numRows, numCols];
        var sortedByLinqOnListOfRows = listOfRows.AsParallel().OrderBy(r => r.Values[0]).ThenByDescending(r => r.Values[2]).ThenBy(r => r.Values[1]);
        ListOfRowsToTwoDimensionalArray(sortedByLinqOnListOfRows, ref aSortedUsingLinqOnListOfRows);
        Console.WriteLine("nLinq on list of custom type:");
        PrintMultiDimensionalArray(aSortedUsingLinqOnListOfRows);
        var aSortedUsingDLinqOnListOfRows = new IComparable[numRows, numCols];
        var sortedByDLinqOnListOfRows = listOfRows.AsParallel().OrderBy("Values[0] ASC, Values[2] DESC, Values[1] ASC");
        ListOfRowsToTwoDimensionalArray(sortedByDLinqOnListOfRows, ref aSortedUsingDLinqOnListOfRows);
        Console.WriteLine("nnDLinq on list of custom type:");
        PrintMultiDimensionalArray(aSortedUsingDLinqOnListOfRows);
        var listOfList = TwoDimensionalArrayToListOfList(testArray);
        var aSortedUsingLinqOnListOfList = new IComparable[numRows, numCols];
        var sortedByLinqOnListOfList = listOfList.AsParallel().OrderBy(r => r[0]).ThenByDescending(r => r[2]).ThenBy(r => r[1]);
        ListOfListToTwoDimensionalArray(sortedByLinqOnListOfList, ref aSortedUsingLinqOnListOfList);
        Console.WriteLine("nnLinq on list of list:");
        PrintMultiDimensionalArray(aSortedUsingLinqOnListOfList);
        var aSortedUsingDLinqOnListOfList = new IComparable[numRows, numCols];
        var sortedByDLinqOnListOfList = listOfList.AsParallel().OrderBy("0 ASC, 2 DESC, 1 ASC"); //The string provided is incorrect here
        ListOfListToTwoDimensionalArray(sortedByDLinqOnListOfList, ref aSortedUsingDLinqOnListOfList);
        Console.WriteLine("nnDLinq on list of list (incorrect):");
        PrintMultiDimensionalArray(aSortedUsingDLinqOnListOfList);
        var jaggedArray = TwoDimensionalArrayToJagged(testArray);
        var aSortedUsingLinqOnJagged = new IComparable[numRows, numCols];
        var sortedJaggedLinq = jaggedArray.AsParallel().OrderBy(r => r[0]).ThenByDescending(r => r[2]).ThenBy(r => r[1]);
        JaggedArrayToTwoDimensional(sortedJaggedLinq, ref aSortedUsingLinqOnJagged);
        Console.WriteLine("nnLinq on jagged array:");
        PrintMultiDimensionalArray(aSortedUsingLinqOnJagged);
        var aSortedUsingDLinqOnJagged = new IComparable[numRows, numCols];
        var sortedUsingDLinqOnJagged = jaggedArray.AsParallel().OrderBy("0 ASC, 2 DESC, 1 ASC"); //The string provided is incorrect here
        JaggedArrayToTwoDimensional(sortedUsingDLinqOnJagged, ref aSortedUsingDLinqOnJagged);
        Console.WriteLine("nnDLinq on jagged array(incorrect):");
        PrintMultiDimensionalArray(aSortedUsingDLinqOnJagged);
        Console.Read();
    }
    static void PrintMultiDimensionalArray(IComparable[,] a)
    {
        int rowStart = a.GetLowerBound(0);
        int rowEnd = a.GetUpperBound(0);
        int colStart = a.GetLowerBound(1);
        int colEnd = a.GetUpperBound(1);
        for (int r = rowStart; r <= rowEnd; r++)
        {
            if (colStart != colEnd)
            {
                for (int c = colStart; c < colEnd; c++)
                    Console.Write("{0}, ", a[r, c]);
            }
            Console.WriteLine(a[r, colEnd]);
        }
    }
    static void JaggedArrayToTwoDimensional(IEnumerable<IComparable[]> jagged, ref IComparable[,] a)
    {
        int rowStart = a.GetLowerBound(0);
        int colStart = a.GetLowerBound(1);
        int rowIndex = rowStart;
        foreach (var row in jagged)
        {
            int colIndex = colStart;
            foreach (var val in row)
            {
                a[rowIndex, colIndex++] = val;
            }
            rowIndex++;
        }
    }
    static void ListOfListToTwoDimensionalArray(IEnumerable<List<IComparable>> rows, ref IComparable[,] a)
    {
        int r = 0;
        foreach (var row in rows)
        {
            int c = 0;
            foreach (var val in row)
                a[r, c++] = val;
            r++;
        }
    }
    static void ListOfRowsToTwoDimensionalArray(IEnumerable<Row> rows, ref IComparable[,] a)
    {
        int r = 0;
        foreach (var row in rows)
        {
            int c = 0;
            foreach (var val in row.Values)
                a[r, c++] = val;
            r++;
        }
    }
    static List<Row> TwoDimensionalArrayToListOfRows(IComparable[,] a)
    {
        int rowStart = a.GetLowerBound(0);
        int rowEnd = a.GetUpperBound(0);
        var l = new List<Row>(rowEnd - rowStart + 1);
        for (int r = rowStart; r <= rowEnd; r++)
            l.Add(new Row(a, r));
        return l;
    }
    static List<List<IComparable>> TwoDimensionalArrayToListOfList(IComparable[,] a)
    {
        int rowStart = a.GetLowerBound(0);
        int rowEnd = a.GetUpperBound(0);
        int numRows = rowEnd - rowStart + 1;
        int colStart = a.GetLowerBound(1);
        int colEnd = a.GetUpperBound(1);
        int numCols = colEnd - colStart + 1;
        var l = new List<List<IComparable>>(numRows);
        for (int r = rowStart; r <= rowEnd; r++)
        {
            var row = new List<IComparable>(numCols);
            for (int c = colStart; c <= colEnd; c++)
                row.Add(a[r, c]);
            l.Add(row);
        }
        return l;
    }
    static IComparable[][] TwoDimensionalArrayToJagged(IComparable[,] a)
    {
        int rowStart = a.GetLowerBound(0);
        int rowEnd = a.GetUpperBound(0);
        int numRows = rowEnd - rowStart + 1;
        int colStart = a.GetLowerBound(1);
        int colEnd = a.GetUpperBound(1);
        int numCols = colEnd - colStart + 1;
        var jagged = new IComparable[numRows][];
        for (int r = rowStart; r <= rowEnd; r++)
        {
            int rowIndex = r - rowStart;
            jagged[rowIndex] = new IComparable[numCols];
            for (int c = colStart; c <= colEnd; c++)
                jagged[rowIndex][c - colStart] = a[r, c];
        }
        return jagged;
    }
    public class Row
    {
        public Row(IComparable[,] a, int rowIndex)
        {
            int colStart = a.GetLowerBound(1);
            int colEnd = a.GetUpperBound(1);
            Values = new IComparable[colEnd - colStart + 1];
            for (int c = colStart; c <= colEnd; c++)
                Values[c - colStart] = a[rowIndex, c];
        }
        public IComparable[] Values { get; private set; }
    }
}
}

我明白了,你应该使用关键字'it'定义在这里:http://dynamiclinq.azurewebsites.net/Expressions

所以在这种情况下排序字符串将是:"it[0] ASC, it[2] DESC, it[1] ASC"

看到锯齿数组方法在大型数据集上的速度有多快将会很有趣。我怀疑它会比使用DataTable
快得多。

相关内容

  • 没有找到相关文章

最新更新