Combining two single dimensional arrays in a 2D array in c# - c#

I am having two 1D arrays. I want to convert these 2 arrays as single 2D array.
My code is:
public Static void Main()
{
int[] arrayRow;
int[] arrayCol;
for (int i = 0; i < row; i++)
{
for (int j = 0; j < column; j++)
{
int[,] myArray = new int[row,column];
myArray[i,j] = arrayRow[i]; // not possible -- your suggestions
}
}
for (int i = 0; i < row; i++)
{
for (int j = 0; j < column; j++)
{
Console.Write(myArray[i,j]);
}
}
}
I need to save arrayRow[] and arrayCol[] in myArray[,].
For example,
if we have arrayRow[]={1,2,3} and arrayCol[]={4,5,6} then myArray[,]={(1,4),(2,5),(3,6)}
Note: arrayRow and arrayCol may have different lengths. In such cases the element that have no pair should be stored in the new single dimensional array result[].

Your arrayRow[] and arrayCol[] will be just two lines of a two-dimensional array (if you didn't mean jagged one).
So the code to unite two arrays into one is just:
public static T[,] Union<T>(T[] first, T[] second) //where T : struct
{
T[,] result = new T[2, Math.Max(first.Length, second.Length)];
int firstArrayLength = first.Length * Marshal.SizeOf(typeof(T));
Buffer.BlockCopy(first, 0, result, 0, firstArrayLength);
Buffer.BlockCopy(second, 0, result, firstArrayLength, second.Length * Marshal.SizeOf(typeof(T)));
return result;
}
As it have been mentinoned, BlockCopy is cooler than for cycle.
If you do mean that you need a jagged array (like int[][]), that the solutiona will be way more simplier:
public static T[][] UnionJagged<T>(T[] first, T[] second)
{
return new T[2][] { first, second };
}
Which transforms into even simplier if we add multiple-array-as-parameters functionality:
public static T[][] UnionJagged<T>(params T[][] arrays)
{
return arrays;
}
static void Main()
{
int[] a = new int[] { 10, 2, 3 };
int[] b = new int[] { -1, 2, -3 };
int[] c = new int[] { 1, -2, 3 };
int[][] jaggedThing = UnionJagged(a, b, c);
}

Didn't tryed this, and I'm just guessing what you want to acomplish, but here it is:
int[] arrayRow;
int[] arrayCol;
int[,] myArray = new int[Math.Max(arrayRow.Length, arrayCol.Length), 2];
for (int i = 0; i < arrayRow.Length; i++)
myArray[i, 0] = arrayRow[i];
for (int i = 0; i < arrayCol.Length; i++)
myArray[i, 1] = arrayCol[i];

More performant / another way:
public static void ConvertFlatArrayToMatrix(int[] array, int[,] matrix, int dimension) {
for(int i = 0; i < array.Length; i++) {
int r = Mathf.FloorToInt(i / dimension);
int c = i % dimension;
matrix[c,r] = array[i];
}
}
This will just push the result into a 2d array you pass in.
Keep in mind, I'm not checking length or protecting against anything here, this is just the concept and the bare minimum to get the job done.

Related

Pass an array to a function, reverse it without using the Array.Reverse() method and return the reversed array

I want to pass an array to a function, reverse it without using the Array.Reverse() method and return the reversed array. I am actually trying to do it without using the temp variable in this case.
Below is my code snippet. Please correct me where I am getting it wrong.
class Program
{
static void Main(string[] args)
{
int[] array = { 1, 2, 3, 4, 5 };
int[] reverse = new int[5];
reverse = ReverseArray(array, reverse);
foreach (int item in reverse)
{
Console.WriteLine(reverse);
}
}
public static int[] ReverseArray(int[] arr, int[] rev)
{
int x = arr.Length - 1;
for (int i = 0; i <= x; i++)
{
rev[i] = arr[x];
x--;
}
return rev;
}
}
I am actually trying to do it without using the temp variable in this case.
Let's ignore this bit first, and use a temp variable where it makes sense. We can come back to it.
There are a few different ways in which we can deal with the general problem of "reverse an array". We can reverse the array itself in-place, we can create a new array that is the reverse of the array we were given, or we can fill in another array we are given to be the reverse of the first array we were given. Your solution has a mixture of the three, and hence manages to do none of them properly.
To fill in a second array we are given we do not need a temp, as we aren't swapping, and we do not want to stop at a middle point:
static void Main(string[] args)
{
int[] array = { 1, 2, 3, 4, 5 };
int[] reverse = new int[5];
ReverseArray(array, reverse);
foreach (int item in reverse)
{
Console.WriteLine(item);
}
}
public static void ReverseArray(int[] arr, int[] rev)
{
int x = arr.Length - 1;
for (int i = 0; i < arr.Length; i++, x--)
{
rev[i] = arr[x];
}
}
We've gone through every single element in arr and put it in the relevant position in rev.
To return a new array we do much the same thing, but creating the new array within the method itself:
static void Main(string[] args)
{
int[] array = { 1, 2, 3, 4, 5 };
int[] reverse = ReverseArray(array);
foreach (int item in reverse)
{
Console.WriteLine(item);
}
}
public static int[] ReverseArray(int[] arr)
{
int[] rev = new int[arr.Length];
int x = arr.Length - 1;
for (int i = 0; i < arr.Length; i++, x--)
{
rev[i] = arr[x];
}
return rev;
}
A variant of this doesn't create a new array at all, but just iterates through it, producing an IEnumerable<int>. This is faster to return the first result and doesn't use as much memory with large arrays, but re-does the reversing every time it's used, so it varies in how useful it is accordingly:
static void Main(string[] args)
{
int[] array = { 1, 2, 3, 4, 5 };
IEnumerable<int> reverse = ReverseArray(array);
foreach (int item in reverse)
{
Console.WriteLine(item);
}
}
public static IEnumerable<int> ReverseArray(int[] arr)
{
for (int i = arr.Length - 1; i >= 0; i--)
{
yield return arr[i];
}
}
To reverse an array in-place we want to work our way from the outside to the middle swapping elements:
static void Main(string[] args)
{
int[] array = { 1, 2, 3, 4, 5 };
ReverseArray(array);
foreach (int item in array)
{
Console.WriteLine(item);
}
}
public static void ReverseArray(int[] arr)
{
int x = arr.Length - 1;
for (int i = 0; i < x; i++, x--)
{
int temp = arr[x];
arr[x] = arr[i];
arr[i] = temp;
}
}
This breaks your arbitrary no-temp-variable rule. We can get around this with a little trick of bit-twiddling, though there's no real value in doing that.
static void Main(string[] args)
{
int[] array = { 1, 2, 3, 4, 5 };
ReverseArray(array);
foreach (int item in array)
{
Console.WriteLine(item);
}
}
public static void ReverseArray(int[] arr)
{
int x = arr.Length - 1;
for (int i = 0; i < x; i++, x--)
{
arr[x] ^= arr[i];
arr[i] ^= arr[x];
arr[x] ^= arr[i];
}
}
There's really no value in not using a 4-byte temporary variable though.
The x might not need to decrement, you can use arr.Length - 1 - i instead of x for array index otherwise, you will only revered half array.
public static int[] ReverseArray(int[] arr, int[] rev)
{
int x = arr.Length - 1;
for (int i = 0; i <= x; i++)
{
rev[i] = arr[arr.Length - 1 - i];
}
return rev;
}
and I would only pass one array be for method and you can declare the reverse array in the method.
public static int[] ReverseArray(int[] arr)
{
int[] reverse = new int[arr.Length];
int x = arr.Length - 1;
for (int i = 0; i <= x; i++)
{
reverse[i] = arr[arr.Length - 1 - i];
}
return reverse;
}
c# online
Result
5
4
3
2
1

Convert List<string>[] to double[,] [duplicate]

Is there an one-liner (no looping) that converts List<double[]> to double[,]?
Converting to double[,] can only be done by looping through the list and requires that all arrays contained in the list are of same size:
double[,] arr = new double[list.Count, list[0].Length];
for (int i = 0; i < list.Count; i++)
{
for (int j = 0; j < list[0].Length; j++)
{
arr[i, j] = list[i][j];
}
}
Of course, you can easily create a jagged double[][] array of arrays by calling .ToArray():
double[] array = new double[] { 1.0, 2.0, 3.0 };
double[] array1 = new double[] { 4.0, 5.0, 6.0 };
List<double[]> list = new List<double[]>();
list.Add(array);
list.Add(array1);
double[][] jaggedArray = list.ToArray();
Well, you probably can't implement it without loops, but you can make the usage a one-liner :
double[,] array = list.To2DArray();
To2DArray is an extension method implemented as follows:
public static class ExtensionMethods
{
public static T[,] To2DArray<T>(this IEnumerable<IEnumerable<T>> source)
{
var jaggedArray = source.Select(r => r.ToArray()).ToArray();
int rows = jaggedArray.GetLength(0);
int columns = jaggedArray.Max(r => r.Length);
var array = new T[rows, columns];
for (int i = 0; i < rows; i++)
{
for (int j = 0; j < jaggedArray[i].Length; j++)
{
array[i, j] = jaggedArray[i][j];
}
}
return array;
}
}
Note that it will only work in C# 4, since earlier versions don't support covariance. This variant should work in C# 3 but it is more specific:
public static T[,] To2DArray<T>(this IEnumerable<T[]> source)
{
var jaggedArray = source.ToArray();
// same code from here
}
If a 2 dim array is to be created from List of 1 dim array then looping is required, though it may not look like that at the call-site.
public static T[,] ToMultidimensional<T>(this T[][] arr, int maxSize)
{
T[,] md = (T[,])Array.CreateInstance(typeof(double), arr.Length, maxSize);
for (int i = 0; i < arr.Length; i++)
for (int j = 0; j < arr[i].Length; j++)
md[i, j] = arr[i][j];
return md;
}
var arr = new List<double[]>
{
new double[] { 1, 2, 3 },
new double[] { 4, 5 }
}
.ToArray();
var j = arr.ToMultidimensional(arr.Max(a => a.Length));
This syntax should work:
return new List{new double[] { minX, minY }, new double[] { maxX, maxY }};

Get sub array from a 3D array

If I have an array:
int[,,] mainArray = new int[10,10,3];
How can I get a sub array:
int[] sub = mainArray[0,1]; // Unfortunately this doesn't work
Where sub would contain the 3 elements
sub[0] = mainArray[0,1,0];
sub[1] = mainArray[0,1,1];
sub[2] = mainArray[0,1,2];
It would be easy to write a method to do this but is there a built in way to do it?
I think you can use an extension method like this:
public static class MyExtensions
{
public static int[] GetValues(this Array source, int x, int y)
{
var length = source.GetUpperBound(2);
var values = new int[length+1];
for (int i = 0; i < length+1; i++)
{
values[i] = (int)source.GetValue(x, y, i);
}
return values;
}
}
Usage:
int[,,] mainArray = new int[10,10,3];
int[] sub = mainArray.GetValues(0, 1);
You could use nested arrays instead.
// Initialization
int[][][] mainArray = new int[10][][];
for (int i = 0; i < mainArray.Length; i++)
{
mainArray[i] = new int[10][];
for (int j = 0; j < mainArray[i].Length; j++)
{
mainArray[i][j] = new int[3];
}
}
// Usage
int[] sub = mainArray[0][1];
Yes, the initialization is a bit more complex, but other than that it's all the same. And nested arrays even have better performance (but you shouldn't care about array performance unless your profiler told you so).
Here is a helper class I wrote to help with the initialization of nested arrays.
public static class NestedArray
{
public static Array Create<T>(params int[] lengths)
{
Type arrayType = typeof(T);
for (int i = 0; i < lengths.Length - 1; i++)
arrayType = arrayType.MakeArrayType();
return CreateArray(arrayType, lengths[0], lengths.Skip(1).ToArray());
}
private static Array CreateArray(Type elementType, int length, params int[] subLengths)
{
Array array = Array.CreateInstance(elementType, length);
if (subLengths.Length > 0)
{
for (int i = 0; i < length; i++)
{
Array nestedArray = CreateArray(elementType.GetElementType(), subLengths[0], subLengths.Skip(1).ToArray());
array.SetValue(nestedArray, i);
}
}
return array;
}
}
Usage:
int[][][] mainArray = (int[][][])NestedArray.Create<int>(10, 10, 3);
Full commented source code can be found in this gist.
You can use Buffer.BlockCopy and some math, if you always want the the last dimension:
Buffer.BlockCopy(mainArray, (D2*i+j)*D3*sizeof(TYPE), sub, 0, D3*sizeof(TYPE));
will put mainArray[i,j,] in sub, where D1, D2, and D3 are your dimensions and TYPE is the type of the array elements.

Generic initialization of multidimensional array

I have a multidimensional array, which I want to initialize in a simple and fast way:
double[,,] arr = new double[4,5,6];
// doesn't work by design
foreach(double d in arr)
d = ... ; // my initialization value
This obviously doesn't works. But I would like to have a generic function for setting all array values to a choosen default. With own classes, I could write a special constructor, but with value types I've no real idea. With C++, I could access all items in a linear way with one for loop, but in C# I think I've to use as much for loops as I have dimensions. I've no better solution at the moment ( or I'm using unsafe code and pointer arithmetics, which would probably work.).
Is there a more elegant way for doing this ?
Not quite sure if it's what you want, but the following extension method will allow you to initialise every value in an array, regardless of the number of dimensions.
public static class ArrayExtensions
{
public static void Set<T>(this Array array, T defaultValue)
{
int[] indicies = new int[array.Rank];
SetDimension<T>(array, indicies, 0, defaultValue);
}
private static void SetDimension<T>(Array array, int[] indicies, int dimension, T defaultValue)
{
for (int i = 0; i <= array.GetUpperBound(dimension); i++)
{
indicies[dimension] = i;
if (dimension < array.Rank - 1)
SetDimension<T>(array, indicies, dimension + 1, defaultValue);
else
array.SetValue(defaultValue, indicies);
}
}
}
Use like so:
int[, ,] test1 = new int[3, 4, 5];
test1.Set(1);
int[,] test2 = new int[3, 4];
test2.Set(1);
int[] test3 = new int[3];
test3.Set(1);
I would strongly recommend using a 1D array, and map the values sequentially. You will need to convert from indeces i, j, k, ... into the proper array index, which is done with the Que() function below, part of a generic array class SeqArray<T>.
// Test code first
class Program
{
static void Main(string[] args)
{
/* 3 pages, of a 4x2 matrix
*
* |16 17|
* | 8 9|19|
* | 0 1|11|21|
* | 2 3|13|23|
* | 4 5|15|
* | 6 7|
*
* shown above are the sequential indeces for a rank 3 array
*/
SeqArray<double> arr = new SeqArray<double>(3, 4, 2);
// Initialize values to squential index "num"
int num = 0;
for (int i = 0; i < 3; i++)
{
for (int j = 0; j < 4; j++)
{
for (int k = 0; k < 2; k++)
{
arr[i, j, k] = num++;
}
}
}
// Check that the array values correspond to the index sequence
num = 0;
for (int i = 0; i < 3 * 4 * 2; i++)
{
Trace.Assert(arr.InnerArray[i] == num++);
}
// Initialize with value=π
arr = new SeqArray<double>(Math.PI, 4, 5, 6);
}
}
public class SeqArray<T>
{
T[] values;
int[] lengths;
public SeqArray(params int[] lengths)
{
this.lengths = lengths;
int N = 1;
for (int i = 0; i < lengths.Length; i++)
{
N *= lengths[i];
}
values = new T[N];
}
public SeqArray(T value, params int[] lengths) : this(lengths)
{
for (int i = 0; i < values.Length; i++)
{
values[i] = value;
}
}
public int[] Lengths { get { return lengths; } }
public int Size { get { return values.Length; } }
internal T[] InnerArray { get { return values; } }
public int Que(params int[] indeces)
{
// Check if indeces are omited like arr[4] instead of arr[4,0,0]
if (indeces.Length < lengths.Length)
{
// Make a new index array padded with zeros
int[] temp = new int[lengths.Length];
indeces.CopyTo(temp, 0);
indeces = temp;
}
// Count the elements for indeces
int k = 0;
for (int i = 0; i < indeces.Length; i++)
{
k = lengths[i] * k + indeces[i];
}
return k;
}
public T this[params int[] indeces]
{
get { return values[Que(indeces)]; }
set { values[Que(indeces)] = value; }
}
}
Here is a non-recursive version alternative to that posted by Andy Holt above:
public static void SetAll<T>(this Array array, T value)
{
var sizes = new int[array.Rank];
sizes[array.Rank - 1] = 1;
for (var d = array.Rank - 2; d >= 0; d--)
{
sizes[d] = array.GetLength(d + 1)*sizes[d + 1];
}
for (var i = 0; i < array.Length; i++)
{
var remainder = i;
var index = new int[array.Rank];
for (var d = 0; d < array.Rank && remainder > 0; d++)
{
index[d] = remainder / sizes[d];
remainder -= index[d]*sizes[d];
}
array.SetValue(value, index);
}
}

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