1

I want to be able to sort a 2D array on two columns. I have managed to do it on one column using the code extensions from CodeProject

using System.IO;
using OfficeOpenXml;

namespace TestEPPlus
{
    class Program
    {
        static void Main(string[] args)
        {
            ExcelPackage package = new ExcelPackage(new FileInfo(@"C:\IAIN\Test.xlsx"));
            ExcelWorksheet workSheet = package.Workbook.Worksheets["Sheet1"];

            object[,] myArray = workSheet.Cells.Value as object[,];

            // Sorts the Array by Column 1
            var myResult = myArray.OrderBy(x => x[1]);

        }
    }
}

The Orderedby line in this example sorts on Column 1. I would like to sort on Column 1 and Column 4.

enter image description here

I am committed to using EPPlus to read a very large spreadsheet and it does not support sorting unfortunately.

Thanks All,

bibble235
  • 788
  • 9
  • 15
  • Provide an example of what you need, since you are using the 2 Dimensional array, not a jagged array of type [][], how can you sort on more than one axis for a 2D array – Mrinal Kamboj Sep 22 '16 at 05:24
  • Thanks for looking updated the question to be clearer – bibble235 Sep 22 '16 at 06:43
  • 1
    I would start off by converting the `object[,]` into a more useful form, e.g. a collection of rows, ideally of some specific type. Then you can easily order the rows and work with them in all kinds of ways. Isolate the unhelpful representatoin (`object[,]`) to as small a piece of your code as possible - basically loading and saving. – Jon Skeet Sep 22 '16 at 07:11
  • Check http://stackoverflow.com/questions/8866414/how-to-sort-2d-array-in-c-sharp – Mrinal Kamboj Sep 22 '16 at 07:37

3 Answers3

0

The simplest way would be to call the OrderBy extension method twice. Since linq uses a stable sorting algorithm, the order of the elements after the first call will remain for elements that have equal values in the second call.

matrix.OrderBy(r => r[4]).OrderBy(r => r[1]);

Do note that for this you need to order in reverse of what you would do normally: For a (one dimensional) enumerable you would prefer to write this as matrix.OrderBy(r => r[1]).ThenBy(r => r[4]);

You could of course write your own OrderBy and ThenBy extension methods to work on two-dimensional arrays. That would be more readable in usage, but also more work, so I'll leave that to others to do...

Steven
  • 2,437
  • 5
  • 32
  • 36
  • 1
    Calling twice, not sure this would work as I think this would just re-order based on **only** second column rather than take into account the first key – bibble235 Sep 22 '16 at 07:26
  • It does work; try it. The order of the first keys is kept for items that are equal according to the second key, because it uses a stable sorting algorithm. – Steven Sep 22 '16 at 07:29
  • Did you try applying `OrderBy` to the multi dimensional array provided in the question, it doesn't even exist – Mrinal Kamboj Sep 22 '16 at 07:36
  • @Mrinal he uses custom extension methods from the website linked in his question – Steven Sep 22 '16 at 07:37
  • If he's already using someone's code, then where's the question – Mrinal Kamboj Sep 22 '16 at 07:39
  • @Mrinal because that code doesn't quite do what he wants it to do the way he used it – Steven Sep 22 '16 at 07:40
  • I did try two Orderby's and it did not produce the result I wanted but instead resorted on the second column without accounting for the first column sort. i.e. myArray.OrderBy(x => x[1]).OrderBy(x => x[2]); is the same as myArray.OrderBy(x => x[2]) and yes I probably need to implement ThenBy on the existing extension – bibble235 Sep 22 '16 at 20:48
0

I solved this by modifying the example from CodeProject and adding a list on indexes to sort on. Hope it helps someone else.

    public static T[,] OrderBy<T>(this T[,] source, Func<T[], T> inKeySelector, IList<int> inThenByColumns)
    {
        var mySingleDimensionArray = source.ConvertToSingleDimension().OrderBy(inKeySelector);
        if (inThenByColumns.Count > 0)
        {
            mySingleDimensionArray = inThenByColumns.Aggregate(
                mySingleDimensionArray, 
                (myCurrent, myColumn) => myCurrent.ThenBy(x => x[myColumn]));
        }
        return mySingleDimensionArray.ConvertToMultiDimensional();
    }
bibble235
  • 788
  • 9
  • 15
-1

To sort on multiple column we can use ThenBy/ThenByDescending followed by orderby refer below example

myArray.OrderBy(x => x[1]).ThenBy(x => x[2]);
Hemant D
  • 192
  • 5