C# multi-dimension array sort based on user input - c#

How can I sort a 2D array in C#
I have looked at other answers to this question but they don't do exactly what I need.
The array is variable height * 5 across
The array holds strings
I need the array sorted based on either column, for example sort in alphabetical the third column, however all other columns must be updated.
Does anyone know of a quick and easy solution?
My code is a mess, here is a shortened version:
string[,] tmp = new string[2, 3];//this is filled with strings
string y = Console.ReadLine();
int x = Convert.ToInt32(y);
// sort tmp based on x column

How do I sort a two-dimensional array in C#? contains a possible solution to this by reading your data into a datatable and then using the object's methods to sort:
// assumes stringdata[row, col] is your 2D string array
DataTable dt = new DataTable();
// assumes first row contains column names:
for (int col = 0; col < stringdata.GetLength(1); col++)
{
dt.Columns.Add(stringdata[0, col]);
}
// load data from string array to data table:
for (rowindex = 1; rowindex < stringdata.GetLength(0); rowindex++)
{
DataRow row = dt.NewRow();
for (int col = 0; col < stringdata.GetLength(1); col++)
{
row[col] = stringdata[rowindex, col];
}
dt.Rows.Add(row);
}
// sort by third column:
DataRow[] sortedrows = dt.Select("", "3");
// sort by column name, descending:
sortedrows = dt.Select("", "COLUMN3 DESC");

So first we'll want to convert the multi-dimensional array into a sequence of single-dimensional arrays representing the rows, so that each row can be manipulated as a unit:
public static IEnumerable<T[]> GetRows<T>(T[,] array)
{
for (int i = 0; i < array.GetLength(0); i++)
{
T[] row = new T[array.GetLength(1)];
for (int j = 0; j < row.Length; j++)
{
row[j] = array[i, j];
}
yield return row;
}
}
Then we'll also need a method that does the reverse to get a multi-dimensional array back when we're done:
public static T[,] ToMultiDimensionalArray<T>(T[][] rows)
{
T[,] output = new T[rows.Length, rows[0].Length];
for (int i = 0; i < rows.Length; i++)
for (int j = 0; j < rows[0].Length; j++)
{
output[i, j] = rows[i][j];
}
return output;
}
Now we just need to sort a sequence of arrays, and Linq makes this quite easy:
tmp = ToMultiDimensionalArray(GetRows(tmp)
.OrderBy(row => row[2]).ToArray());

Related

How to combine multiple arrays (that represent columns of data) into a nested/jagged array (or even a 2D) array

I have a program that I'm writing to extract certain data from various excel spreadsheet.
The process so far is:
for each spreadsheet identified:
-read in the data as a multidimensional array using interop excel (Even though it is slow, it is the best choice due to all of the different file formats I need to read in)
Sample: object[,] cellValues = (object[,])range.Value2;
-Identify the columns that I actually need and what order I need them in. This is stored in a jagged array of bytes:
byte[][] targetColumns
-THe jagged array essentially is (columnIndexFromSpreadsheet, preferredColumnOrder) e.g. if the first column in the spreadsheet should be read in as column 10 it would be (1, 10)
-I sort the jagged array by the preferred column order (that way I can just loop through the array in that order and extract those columns):
public static byte[][] SortTargetColumns(byte[][] targetColumns)
{
return targetColumns.OrderBy(x => x.Skip(1).First()).ToArray();
}
-I then extract that column by creating an array from that column index of the multidimensional array. This is the method that is called:
public static object[] ExtractColumn(object[,] dataArray ,byte columnIndex)
{
return Enumerable.Range(ArrayIndexStart, dataArray.GetLength(0)).Select(x => dataArray[x, columnIndex]).ToArray();
}
Usage:
array = ExtractColumn(dataArray, (byte) colIndex);
Now I am trying to piece these extracted arrays back together to make it readable. I will need to do some manipulation on some of the columns and then write to a text file after consolidating. The only problem is that I have no idea how to do this correctly. I have tried the following methods but continue to get a null reference exception:
// Get Row Count of dataArray
int rowCount = dataArray.GetLength(0);
// Create List to store extracted arrays
List<object[]> extractedDataList = new List<object[]>();
// Loop through target columns and extract the column as an array
for (byte colIndex = 1; colIndex <= targetColumns.Length + 1; colIndex++)
{
object[] array = ExtractColumn(dataArray, (byte) colIndex);
extractedDataList.Add(array);
}
// Create jagged array
object[][] extractedDataArray = new object[rowCount][] ;
for(int i = 0; i < extractedDataArray.GetLength(0); i++)
{
List<object> row = new List<object>();
for (int j = 0; j < extractedDataList.Count; j++)
{
row.Add(extractedDataList[j][i].ToString());
//extractedDataArray[i][j] = extractedDataList[j][i].ToString(); <-- null reference
}
extractedDataArray[i] = row.ToArray();
}
I'm at a loss of what else to try to put these column arrays back in a form that I can easily work with. Any and all tips/recommendations would be greatly appreciated.
Whenever you get confused like this, break the problem down into small pieces, and use meaningful names.
Let's say you have an array of columns, each of which has one element per row. That might be declared like this:
object[][] columns;
First, let's get the row and column counts:
var columnCount = columns.Length;
var rowCount = columns[0].Length;
Now write a small local function to accept a row and column index and return the right cell. In case not all of your columns have the same number of rows, you can include a boundary check and just return null if a cell isn't there.
object Getter(int row, int col)
{
bool outOfBounds = (row >= columns[col].Length);
return outOfBounds ? null : columns[col][row];
}
Now all we have to do is iterate over the rows to create the inner arrays:
object[][] target = new object[rowCount][]
for (int row = 0; row < rowCount; row++)
{
target[row] = new object[columnCount];
}
And add in the code that uses the getter to populate the cells:
object[][] target = new object[rowCount][];
for (int row = 0; row < rowCount; row++)
{
target[row] = new object[columnCount];
for (int col = 0; col < columnCount; col++)
{
var cellValue = Getter(row, col);
target[row][columnCount] = cellValue;
}
}
All together, it is simple to read:
var columnCount = columns.Length;
var rowCount = columns[0].Length;
object Getter(int row, int col)
{
bool outOfBounds = (row >= columns[col].Length);
return outOfBounds ? null : columns[col][row];
}
object[][] target = new object[rowCount][];
for (int row = 0; row < rowCount; row++)
{
target[row] = new object[columnCount];
for (int col = 0; col < columnCount; col++)
{
var cellValue = Getter(row, col);
target[row][columnCount] = cellValue;
}
}

How to make a Jagged Array?

Thinking like a simple array:
Console.WriteLine("Number: ");
int x = Convert.ToInt32(Console.ReadLine());
string[] strA = new string[x];
strA[0] = "Hello";
strA[1] = "World";
for(int i = 0;i < x;i++)
{
Console.WriteLine(strA[i]);
}
Now, how can I do it with a double array?
I've already tried this:
Console.WriteLine("Number 1: ");
int x = Convert.ToInt32(Console.ReadLine());
Console.WriteLine("Number 2: ");
int y = Convert.ToInt32(Console.ReadLine());
// Got an error, right way string[x][];
// But how can I define the second array?
string[][] strA = new string[x][y];
strA[0][0] = "Hello";
strA[0][1] = "World";
strA[1][0] = "Thanks";
strA[1][1] = "Guys";
for(int i = 0;i < x;i++)
{
for(int j = 0;i < y;i++)
{
// How can I see the items?
Console.WriteLine(strA[i][j]);
}
}
If's there's a simpler way of doing this, i'll be happy to learn it.
It's only for knowledge, I'm studying double array for the first time, so have patience please :)
Here's my example:
https://dotnetfiddle.net/PQblXH
You are working with jagged array (i.e. array of array string[][]), not 2D one (which is string[,])
If you want to hardcode:
string[][] strA = new string[][] { // array of array
new string[] {"Hello", "World"}, // 1st line
new string[] {"Thanks", "Guys"}, // 2nd line
};
in case you want to provide x and y:
string[][] strA = Enumerable
.Range(0, y) // y lines
.Select(line => new string[x]) // each line - array of x items
.ToArray();
Finally, if we want to initialize strA without Linq but good all for loop (unlike 2d array, jagged array can contain inner arrays of different lengths):
// strA is array of size "y" os string arrays (i.e. we have "y" lines)
string[][] strA = new string[y][];
// each array within strA
for (int i = 0; i < y; ++i)
strA[i] = new string[x]; // is an array of size "x" (each line of "x" items)
Edit: Let's print out jagged array line after line:
Good old for loops
for (int i = 0; i < strA.Length; ++i) {
Console.WriteLine();
// please, note that each line can have its own length
string[] line = strA[i];
for (int j = 0; j < line.Length; ++j) {
Console.Write(line[j]); // or strA[i][j]
Console.Write(' '); // delimiter, let it be space
}
}
Compact code:
Console.Write(string.Join(Environment.newLine, strA
.Select(line => string.Join(" ", line))));
You're using a jagged array instead of a multidimensional one. Simply use [,] instead of [][]. You can then use it with new string[x, y].
First you need to clarify thing in your head before writing code.
I will recommend writing in simple phrase what you want to do. The code in your fiddle go into every direction. I will address the code in the fiddle and not your questionas you have typo error and other issue that where not present in the fiddle while the fiddle has error that the question do not have.
To simplify the problem lets use clear understandable names. The 2d array will be an table, with rows and columns.
// 1/. Ask for 2table dim sizes.
Console.WriteLine("Enter number of rows:");
var x = int.Parse(Console.ReadLine());
Console.WriteLine("Enter number of columns:");
var y = int.Parse(Console.ReadLine());
var table = new string[x, y];
You need to to declare your table before knowing its size.
// 2/. Fill the board
for (int row = 0; row < table.GetLength(0); row++)
{
for (int col = 0; col < table.GetLength(1); col++)
{
Console.WriteLine($"Enter the value of the cell [{row},{col}]");
table[row, col] = Console.ReadLine();
}
}
table.GetLength(0) is equivalent to X, and table.GetLength(1) is equivalent to Y, and can be replace.
// 3/. Display the Table
Console.Write("\n");
for (int row = 0; row < table.GetLength(0); row++)
{
for (int col = 0; col < table.GetLength(1); col++)
{
Console.Write(table[row, col]);
}
Console.Write("\n");
}
For a 3x3 table with 00X, 0X0, X00 as inputs the result is
00X
0X0
X00
It works. You separate each cell when we display by simply adding a comma or a space.
Fiddle
And for Jagged Array:
// 1/. Ask for 2table dim sizes.
Console.WriteLine("Enter number of rows:");
var x = int.Parse(Console.ReadLine());
var table = new string[x][];
// 2/. Fill the board
for (int row = 0; row < table.GetLength(0); row++)
{
Console.WriteLine($"Enter of the line n°{row}");
var lineSize = int.Parse(Console.ReadLine());
table[row] = new string[lineSize];
for (int col = 0; col < table[row].Length; col++)
{
Console.WriteLine($"Enter the value of the cell [{row},{col}]");
table[row][col] = Console.ReadLine();
}
Console.Write("\n");
}
// 3/. Display the Table
Console.Write("\n");
for (int row = 0; row < table.Length; row++)
{
for (int col = 0; col < table[row].Length; col++)
{
Console.Write(table[row][col]);
}
Console.Write("\n");
}
Wrong variable in use:
for(int j = 0;i < y;i++) <- Should be j
{
// How can I see the items?
Console.WriteLine(strA[i][j]);
}

How to fill a 2D array with class objects inside a for loop?

dailyMenu [,] daysOfMonth = new dailyMenu[4,5];
for (int column = 0; column < daysOfMonth.Length; column++)
{
for (int row = 0; row < daysOfMonth.Length; row++)
{
dailyMenu dm = new dailyMenu ();
}
}
My question is I want to know how to fill my 2D array with new objects of my dailyMenu class?
For the 2-D array, you probably want to get the length by GetLength(0) and GetLength(1) instead of by using Length:
dailyMenu [,] daysOfMonth = new dailyMenu[4,5];
for (int column = 0; column < daysOfMonth.GetLength(0); column++)
{
for (int row = 0; row < daysOfMonth.GetLength(1); row++)
{
dailyMenu dm = new dailyMenu ();
//do something on dm
daysOfMonth[column,row] = dm; //assign it like this
}
}
This is because GetLength has argument of dimension index (0, 1, 2, etc...) Which can give you the length of the array in that dimension (0 being the first dimension - in your case column, and 1 being the second - in your case row. Length does not have that.
To assign a value to the array, simply access the array by the dimension indexes (column and row) in the correct order - otherwise you will get IndexOutOfRange exception:
daysOfMonth[column,row] = dm; //correct
daysOfMonth[row,column] = dm; //wrong, exception on 5,0
My question is I want to know how fill my 2D array with new objects of my dailyMenu class?
After initializing dm.
daysOfMonth[column,row] = dm
You can use .GetLength() to find out the length of a dimension. Alternatively just use the same constants you use in 2D array constructor.
dailyMenu [,] daysOfMonth = new dailyMenu[4,5];
for (int column = 0; column < daysOfMonth.GetLength(0); column++)
{
for (int row = 0; row < daysOfMonth.GetLength(1); row++)
{
daysOfMonth[column,row] = new dailyMenu ();
}
}

Delete row of 2D string array in C#

I am making a program that stores data in a 2D array. I would like to be able to delete rows from this array. I cannot figure out why this code doesn't work:
for (int n = index; n < a.GetUpperBound(1); ++n)
{
for (int i = 0; i < a.GetUpperBound(0); ++i)
{
a[i, n] = a[i, n + 1];
}
}
Could someone please help me out? I would like it to delete a single row and shuffle all the rows below it up one place. Thankyou!
you need to create a new array if you want to delete an item
try something like this
var arrayUpdated = new string[a.GetUpperBound(1)][a.GetUpperBound(0)-1];
for (int n = index; n < a.GetUpperBound(1); n++)
{
for (int i = 0; i < a.GetUpperBound(0); i++)
{
arrayUpdated [i, n] = a[i, 1];
}
}
The nested for loop method here works well: https://stackoverflow.com/a/8000574
Here's a method that converts the outer loop of the [,] array method above to use linq. Using linq here is only recommended if you are also doing other things with linq during the traversal.
public T[,] RemoveRow<T>(T[,] array2d, int rowToRemove)
{
var resultAsList = Enumerable
.Range(0, array2d.GetLength(0)) // select all the rows available
.Where(i => i != rowToRemove) // except for the one we don't want
.Select(i => // select the results as a string[]
{
T[] row = new T[array2d.GetLength(1)];
for (int column = 0; column < array2d.GetLength(1); column++)
{
row[column] = array2d[i, column];
}
return row;
}).ToList();
// convert List<string[]> to string[,].
return CreateRectangularArray(resultAsList); // CreateRectangularArray() can be copied from https://stackoverflow.com/a/9775057
}
used Enumerable.Range to iterate all rows as done in https://stackoverflow.com/a/18673845
Shouldn't ++i be i++? ++i increments before matrix operation is performed(ie pre-increment)

How do I sort a two-dimensional (rectangular) array in C#?

I have a two-dimensional array (of Strings) which make up my data table (of rows and columns). I want to sort this array by any column. I tried to find an algorithm for doing this in C#, but have not been successful.
Any help is appreciated.
Can I check - do you mean a rectangular array ([,])or a jagged array ([][])?
It is quite easy to sort a jagged array; I have a discussion on that here. Obviously in this case the Comparison<T> would involve a column instead of sorting by ordinal - but very similar.
Sorting a rectangular array is trickier... I'd probably be tempted to copy the data out into either a rectangular array or a List<T[]>, and sort there, then copy back.
Here's an example using a jagged array:
static void Main()
{ // could just as easily be string...
int[][] data = new int[][] {
new int[] {1,2,3},
new int[] {2,3,4},
new int[] {2,4,1}
};
Sort<int>(data, 2);
}
private static void Sort<T>(T[][] data, int col)
{
Comparer<T> comparer = Comparer<T>.Default;
Array.Sort<T[]>(data, (x,y) => comparer.Compare(x[col],y[col]));
}
For working with a rectangular array... well, here is some code to swap between the two on the fly...
static T[][] ToJagged<T>(this T[,] array) {
int height = array.GetLength(0), width = array.GetLength(1);
T[][] jagged = new T[height][];
for (int i = 0; i < height; i++)
{
T[] row = new T[width];
for (int j = 0; j < width; j++)
{
row[j] = array[i, j];
}
jagged[i] = row;
}
return jagged;
}
static T[,] ToRectangular<T>(this T[][] array)
{
int height = array.Length, width = array[0].Length;
T[,] rect = new T[height, width];
for (int i = 0; i < height; i++)
{
T[] row = array[i];
for (int j = 0; j < width; j++)
{
rect[i, j] = row[j];
}
}
return rect;
}
// fill an existing rectangular array from a jagged array
static void WriteRows<T>(this T[,] array, params T[][] rows)
{
for (int i = 0; i < rows.Length; i++)
{
T[] row = rows[i];
for (int j = 0; j < row.Length; j++)
{
array[i, j] = row[j];
}
}
}
Load your two-dimensional string array into an actual DataTable (System.Data.DataTable), and then use the DataTable object's Select() method to generate a sorted array of DataRow objects (or use a DataView for a similar effect).
// assumes stringdata[row, col] is your 2D string array
DataTable dt = new DataTable();
// assumes first row contains column names:
for (int col = 0; col < stringdata.GetLength(1); col++)
{
dt.Columns.Add(stringdata[0, col]);
}
// load data from string array to data table:
for (rowindex = 1; rowindex < stringdata.GetLength(0); rowindex++)
{
DataRow row = dt.NewRow();
for (int col = 0; col < stringdata.GetLength(1); col++)
{
row[col] = stringdata[rowindex, col];
}
dt.Rows.Add(row);
}
// sort by third column:
DataRow[] sortedrows = dt.Select("", "3");
// sort by column name, descending:
sortedrows = dt.Select("", "COLUMN3 DESC");
You could also write your own method to sort a two-dimensional array. Both approaches would be useful learning experiences, but the DataTable approach would get you started on learning a better way of handling tables of data in a C# application.
Array.Sort(array, (a, b) => { return a[0] - b[0]; });
Here is an archived article from Jim Mischel at InformIt that handles sorting for both rectangular and jagged multi-dimensional arrays.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
int[,] arr = { { 20, 9, 11 }, { 30, 5, 6 } };
Console.WriteLine("before");
for (int i = 0; i < arr.GetLength(0); i++)
{
for (int j = 0; j < arr.GetLength(1); j++)
{
Console.Write("{0,3}", arr[i, j]);
}
Console.WriteLine();
}
Console.WriteLine("After");
for (int i = 0; i < arr.GetLength(0); i++) // Array Sorting
{
for (int j = arr.GetLength(1) - 1; j > 0; j--)
{
for (int k = 0; k < j; k++)
{
if (arr[i, k] > arr[i, k + 1])
{
int temp = arr[i, k];
arr[i, k] = arr[i, k + 1];
arr[i, k + 1] = temp;
}
}
}
Console.WriteLine();
}
for (int i = 0; i < arr.GetLength(0); i++)
{
for (int j = 0; j < arr.GetLength(1); j++)
{
Console.Write("{0,3}", arr[i, j]);
}
Console.WriteLine();
}
}
}
}
This code should do what you are after, I haven't generalised it for n by n, but that is straight forward. That said - I agree with MusiGenesis, using another object that is a little better suited to this (especially if you intend to do any sort of binding)
(I found the code here)
string[][] array = new string[3][];
array[0] = new string[3] { "apple", "apple", "apple" };
array[1] = new string[3] { "banana", "banana", "dog" };
array[2] = new string[3] { "cat", "hippo", "cat" };
for (int i = 0; i < 3; i++)
{
Console.WriteLine(String.Format("{0} {1} {2}", array[i][0], array[i][1], array[i][2]));
}
int j = 2;
Array.Sort(array, delegate(object[] x, object[] y)
{
return (x[j] as IComparable).CompareTo(y[ j ]);
}
);
for (int i = 0; i < 3; i++)
{
Console.WriteLine(String.Format("{0} {1} {2}", array[i][0], array[i][1], array[i][2]));
}
Can allso look at Array.Sort Method http://msdn.microsoft.com/en-us/library/aa311213(v=vs.71).aspx
e.g. Array.Sort(array, delegate(object[] x, object[] y){ return (x[ i ] as IComparable).CompareTo(y[ i ]);});
from http://channel9.msdn.com/forums/Coffeehouse/189171-Sorting-Two-Dimensional-Arrays-in-C/
So your array is structured like this (I'm gonna talk in pseudocode because my C#-fu is weak, but I hope you get the gist of what I'm saying)
string values[rows][columns]
So value[1][3] is the value at row 1, column 3.
You want to sort by column, so the problem is that your array is off by 90 degrees.
As a first cut, could you just rotate it?
std::string values_by_column[columns][rows];
for (int i = 0; i < rows; i++)
for (int j = 0; j < columns; j++)
values_by_column[column][row] = values[row][column]
sort_array(values_by_column[column])
for (int i = 0; i < rows; i++)
for (int j = 0; j < columns; j++)
values[row][column] = values_by_column[column][row]
If you know you only want to sort one column at a time, you could optimize this a lot by just extracting the data you want to sort:
string values_to_sort[rows]
for (int i = 0; i < rows; i++)
values_to_sort[i] = values[i][column_to_sort]
sort_array(values_to_sort)
for (int i = 0; i < rows; i++)
values[i][column_to_sort] = values_to_sort[i]
In C++ you could play tricks with how to calculate offsets into the array (since you could treat your two-dimensional array as a one-d array) but I'm not sure how to do that in c#.
Try this out. The basic strategy is to sort the particular column independently and remember the original row of the entry. The rest of the code will cycle through the sorted column data and swap out the rows in the array. The tricky part is remembing to update the original column as the swap portion will effectively alter the original column.
public class Pair<T> {
public int Index;
public T Value;
public Pair(int i, T v) {
Index = i;
Value = v;
}
}
static IEnumerable<Pair<T>> Iterate<T>(this IEnumerable<T> source) {
int index = 0;
foreach ( var cur in source) {
yield return new Pair<T>(index,cur);
index++;
}
}
static void Sort2d(string[][] source, IComparer comp, int col) {
var colValues = source.Iterate()
.Select(x => new Pair<string>(x.Index,source[x.Index][col])).ToList();
colValues.Sort((l,r) => comp.Compare(l.Value, r.Value));
var temp = new string[source[0].Length];
var rest = colValues.Iterate();
while ( rest.Any() ) {
var pair = rest.First();
var cur = pair.Value;
var i = pair.Index;
if (i == cur.Index ) {
rest = rest.Skip(1);
continue;
}
Array.Copy(source[i], temp, temp.Length);
Array.Copy(source[cur.Index], source[i], temp.Length);
Array.Copy(temp, source[cur.Index], temp.Length);
rest = rest.Skip(1);
rest.Where(x => x.Value.Index == i).First().Value.Index = cur.Index;
}
}
public static void Test1() {
var source = new string[][]
{
new string[]{ "foo", "bar", "4" },
new string[] { "jack", "dog", "1" },
new string[]{ "boy", "ball", "2" },
new string[]{ "yellow", "green", "3" }
};
Sort2d(source, StringComparer.Ordinal, 2);
}
If you could get the data as a generic tuple when you read it in or retrieved it, it would be a lot easier; then you would just have to write a Sort function that compares the desired column of the tuple, and you have a single dimension array of tuples.
This is an old question, but here's a class I just built based on the article from Jim Mischel at InformIt linked by Doug L.
class Array2DSort : IComparer<int>
{
// maintain a reference to the 2-dimensional array being sorted
string[,] _sortArray;
int[] _tagArray;
int _sortIndex;
protected string[,] SortArray { get { return _sortArray; } }
// constructor initializes the sortArray reference
public Array2DSort(string[,] theArray, int sortIndex)
{
_sortArray = theArray;
_tagArray = new int[_sortArray.GetLength(0)];
for (int i = 0; i < _sortArray.GetLength(0); ++i) _tagArray[i] = i;
_sortIndex = sortIndex;
}
public string[,] ToSortedArray()
{
Array.Sort(_tagArray, this);
string[,] result = new string[
_sortArray.GetLength(0), _sortArray.GetLength(1)];
for (int i = 0; i < _sortArray.GetLength(0); i++)
{
for (int j = 0; j < _sortArray.GetLength(1); j++)
{
result[i, j] = _sortArray[_tagArray[i], j];
}
}
return result;
}
// x and y are integer row numbers into the sortArray
public virtual int Compare(int x, int y)
{
if (_sortIndex < 0) return 0;
return CompareStrings(x, y, _sortIndex);
}
protected int CompareStrings(int x, int y, int col)
{
return _sortArray[x, col].CompareTo(_sortArray[y, col]);
}
}
Given an unsorted 2D array data of arbitrary size that you want to sort on column 5 you just do this:
Array2DSort comparer = new Array2DSort(data, 5);
string[,] sortedData = comparer.ToSortedArray();
Note the virtual Compare method and protected SortArray so you can create specialized subclasses that always sort on a particular column or do specialized sorting on multiple columns or whatever you want to do. That's also why CompareStrings is broken out and protected - any subclasses can use it for simple comparisons instead of typing out the full SortArray[x, col].CompareTo(SortArray[y, col]) syntax.
I like the DataTable approach proposed by MusiGenesis above. The nice thing about it is that you can sort by any valid SQL 'order by' string that uses column names, e.g. "x, y desc, z" for 'order by x, y desc, z'. (FWIW, I could not get it to work using column ordinals, e.g. "3,2,1 " for 'order by 3,2,1') I used only integers, but clearly you could add mixed type data into the DataTable and sort it any which way.
In the example below, I first loaded some unsorted integer data into a tblToBeSorted in Sandbox (not shown). With the table and its data already existing, I load it (unsorted) into a 2D integer array, then to a DataTable. The array of DataRows is the sorted version of DataTable. The example is a little odd in that I load my array from the DB and could have sorted it then, but I just wanted to get an unsorted array into C# to use with the DataTable object.
static void Main(string[] args)
{
SqlConnection cnnX = new SqlConnection("Data Source=r90jroughgarden\\;Initial Catalog=Sandbox;Integrated Security=True");
SqlCommand cmdX = new SqlCommand("select * from tblToBeSorted", cnnX);
cmdX.CommandType = CommandType.Text;
SqlDataReader rdrX = null;
if (cnnX.State == ConnectionState.Closed) cnnX.Open();
int[,] aintSortingArray = new int[100, 4]; //i, elementid, planid, timeid
try
{
//Load unsorted table data from DB to array
rdrX = cmdX.ExecuteReader();
if (!rdrX.HasRows) return;
int i = -1;
while (rdrX.Read() && i < 100)
{
i++;
aintSortingArray[i, 0] = rdrX.GetInt32(0);
aintSortingArray[i, 1] = rdrX.GetInt32(1);
aintSortingArray[i, 2] = rdrX.GetInt32(2);
aintSortingArray[i, 3] = rdrX.GetInt32(3);
}
rdrX.Close();
DataTable dtblX = new DataTable();
dtblX.Columns.Add("ChangeID");
dtblX.Columns.Add("ElementID");
dtblX.Columns.Add("PlanID");
dtblX.Columns.Add("TimeID");
for (int j = 0; j < i; j++)
{
DataRow drowX = dtblX.NewRow();
for (int k = 0; k < 4; k++)
{
drowX[k] = aintSortingArray[j, k];
}
dtblX.Rows.Add(drowX);
}
DataRow[] adrowX = dtblX.Select("", "ElementID, PlanID, TimeID");
adrowX = dtblX.Select("", "ElementID desc, PlanID asc, TimeID desc");
}
catch (Exception ex)
{
string strErrMsg = ex.Message;
}
finally
{
if (cnnX.State == ConnectionState.Open) cnnX.Close();
}
}
I know its late but here is my thought you might wanna consider.
for example this is array
{
m,m,m
a,a,a
b,b,b
j,j,j
k,l,m
}
and you want to convert it by column number 2, then
string[] newArr = new string[arr.length]
for(int a=0;a<arr.length;a++)
newArr[a] = arr[a][1] + a;
// create new array that contains index number at the end and also the column values
Array.Sort(newArr);
for(int a=0;a<newArr.length;a++)
{
int index = Convert.ToInt32(newArr[a][newArr[a].Length -1]);
//swap whole row with tow at current index
if(index != a)
{
string[] arr2 = arr[a];
arr[a] = arr[index];
arr[index] = arr2;
}
}
Congratulations you have sorted the array by desired column. You can edit this to make it work with other data types
Short way, but be careful of performance in big arrays and must have n-count of columns:
This will order it from the last number to the first. In case of need reverse it from 0 to "hero":
for (int i = n-1; i >= 0; i--)
{
resultsAsArray = resultsAsArray.OrderBy(x => x[i]).ToArray();
}
Example (do not be surprised, that 3 is first, 2 after that - those are negative, so -3 is lesser than -2)
var original = new int[][] { new int[] { -3, 1, 2 }, new int[] { -2, -1, 3 }, new int[] { -3, -1, 4 }, new int[] { -3, -2, 5 } };
*var processed = new int[][] { new int[] { -3, -2, 5 }, new int[] { -3, -1, 4 }, new int[] { -3, 1, 2 }, new int[] { -2, -1, 3 } };
Assuming it is a jagged array, you can use LINQ or Array.Sort() method to sort it.
Method 1: Using LINQ
var myOrderedRows = myArray.OrderBy(row => row[columnIndex]).ToArray();
Here, LINQ creates a new IEnumerable which needs to be converted to array (using ToArray()) myOrderedRows. Your original array is still unsorted. More details can be found in docs here.
Method 2: Using Array.Sort()
Array.Sort(myArray, (p, q) => p[columnIndex].CompareTo(q[columnIndex]));
In this case your original array is sorted in place. You can also provide custom Comparer for more comparison rules. More details can be found in docs here.

Categories