Multilevel sorting of array columns
Suppose I am generating this code to generate the idv th random number. But I find it difficult to sort the array, depends on the last column.
let's say the individual size is [idv, width] = [8,6] and I want to sort the whole row with the 6th column ... and I want to take the 4 top list in the array after sorting it. How can I implement this case for code?
public static void population(double[,] individual, int width, int idv, Random rnd)
{
for (int i = 0; i < idv; i++)
{
Console.Write("individual {0} :\t", i+1);
for (int j = 0; j < width; j++)
{
individual[i, j] = Math.Round(rnd.NextDouble() * 10, 2);
Console.Write("{0} ", individual[i, j]);
}
Console.WriteLine("\n");
}
}
thank
source to share
I suggest you use jagged arrays double[][]
instead of 2d double[,]
. Jagged array is an array of arrays that you can easily sort, filter, etc. Usually using Linq:
double[][] individual = new double[][] {
new double[] {81, 82, 83, 84, 85, 86},
new double[] {11, 12, 13, 14, 15, 16},
new double[] {41, 42, 43, 44, 45, 46},
new double[] {31, 32, 33, 34, 35, 36},
new double[] {51, 52, 53, 54, 55, 56},
new double[] {21, 22, 23, 24, 25, 26},
new double[] {61, 62, 63, 64, 65, 66},
new double[] {71, 72, 73, 74, 75, 76},
};
double[][] fragment = individual
.OrderBy(line => line[line.GetUpperBound(0)]) // by last column
.Take(4)
.ToArray();
Another Linq to check the results:
String test = String.Join(Environment.NewLine, fragment
.Select(line => String.Join("\t", line)));
Console.Write(test);
Result
11 12 13 14 15 16
21 22 23 24 25 26
31 32 33 34 35 36
41 42 43 44 45 46
source to share
If you are using multidimensional arrays, there is no easy way to work with them using LINQ, you will need to rely on the good old for
.
static void Main ()
{
// Input array
double[,] u = {
{ 1, 9, 3 },
{ 0, 3, 4 },
{ 3, 4, 5 },
{ 3, 6, 8 },
{ 3, 5, 7 },
};
// Get dimension sizes, specify column to order by
int count = u.GetLength(0), length = u.GetLength(1), orderBy = 2;
// Result array
double[,] v = new double[count, length];
// Construct a list of indices to sort by
var indices = Enumerable.Range(0, count).OrderBy(i => u[i, orderBy]).ToList();
// Copy values from input to output array, based on these indices
for (int i = 0; i < count; i++)
for (int j = 0; j < length; j++)
v[i, j] = u[indices[i], j];
PrintArray(u);
Console.WriteLine();
PrintArray(v);
}
static void PrintArray (double[,] a)
{
for (int i = 0; i < a.GetLength(0); i++) {
for (int j = 0; j < a.GetLength(1); j++)
Console.Write(a[i, j]);
Console.WriteLine();
}
}
If you only want the top 4 rows, you can add Take(4)
before the call ToList()
and adjust the creation of the result array and copy the values into it accordingly.
Multi-element arrays are more efficient and use less memory, so if your arrays are large enough or you need to work with them faster, you may need to write a little more code and use multidimensional matrices instead of jagged arrays, which are easier to work with.
source to share
For a rectangular array, [,]
you can copy the desired column into a one-dimensional array along with the indices, sort it, and then get the rows with the first 4 indices.
static IEnumerable<Tuple<int, double>> GetColumn(int columnIndex, double[,] a)
{
for (int i = a.GetLowerBound(0); i <= a.GetUpperBound(0); i++)
yield return Tuple.Create(i, a[i, columnIndex]);
}
double [,] data = ...;
var column = GetColumn(4, data);
var top4Indices = column.OrderBy(v => v.Second)
.Take(4)
.Select(v => v.First);
foreach (int i in top4Indices)
for (int j = data.GetLowerBound(1); j <= data.GetUpperBound(1); j++)
data[i, j]...
source to share