Using LINQ to Obtain Max of Columns for Two Dimensional Arrays - c#

Is there anyway to use LINQ to obtain the maximum of each columns for two dimensional arrays?
Assume that I have the following:
var arrays = new double[5,100]();
I want to get the maximum of arrays[0,:], arrays[1,:] .... arrays[4,:]. How to use LINQ to do it?
I could have use such method
public double GetMax(double[,] arr, int rowIndex)
{
var colCount = arr.GetLength(1);
double max = 0.0;
for(int i=0; i<colCount; i++)
{
max=Math.Max(Math.Abs(arr[rowIndex, i]), max);
}
return max;
}
But I would prefer a more succinct ways of doing things.

I suppose you could always use Enumerable.Range as a compact form of indexed access:
public static double GetMax(double[,] arr, int rowIndex)
{
return (from col in Enumerable.Range(0, arr.GetLength(1))
select arr[rowIndex, col]).Max();
}
And if you want to get this for all rows:
public static double[] GetMaxForAllRows(double[,] arr, int rowIndex)
{
return (from row in Enumerable.Range(0, arr.GetLength(0))
let cols = Enumerable.Range(0, arr.GetLength(1))
select cols.Max(col => arr[row, col])).ToArray();
}

I don't think there is a built-in way to get a row from a multidimensional array. You can write an extension method though:
public static IEnumerable<T> Row<T>(this T[,] array, int rowIndex)
{
var colCount = array.GetLength(1);
for(int i=0; i<colCount; i++)
{
yield return arr[rowIndex, i];
}
}
And then just use "normal" LINQ:
var max = array.Row(i).Max();

LINQ does not have any methods that cover multi-dimensional arrays.
However, if you can convert it to a list, or maybe roll-your own extensions.

You can use nested "from" statements. Thus iterate through the entire array with range variables representing the respective col/row position within the table. For each of the numbers, you wish to check if it a new max within its row or within its column.

Related

C# LINQ query on multidimensional array

How would I use the following LINQ query correctly? I want to create a one-dimensional array that contains only values that are greater than 5. I can't understand why it can't iterate over this multidimensional array, but if I use foreach, it actually iterates.
// Create an multidimensional array, then just put numbers into it and print the array.
int[,] myArr = new int[5,6];
int rows = myArr.GetLength(0);
int cols = myArr.GetLength(1);
for (int i = 0; i < rows; i++)
{
for (int k = 0; k < cols; k++)
{
myArr[i,k] = i + k;
Console.Write(myArr[i,k]);
}
Console.WriteLine("");
}
var highList = from val in myArr where (val > 5) select val;
The error is:
Could not find an implementation of the query pattern for source type 'int[*,*]'. 'Where' not found. Are you missing a reference or a using directive for 'System.Linq'?
I thought this might fix the problem:
public static IEnumerator<int> GetEnumerator(int[,] arr)
{
foreach(int i in arr)
{
yield return i;
}
}
But it doesn't implement the iterator.
The problem is that multi-dimensional (rectangular) arrays implement IEnumerable, but not IEnumerable<T>. Fortunately, you can use Cast to fix that - and Cast gets called automatically if you explicitly specify the type of the range variable:
var highList = from int val in myArr where (val > 5) select val;
Or without the unnecessary brackets:
var highList = from int val in myArr where val > 5 select val;
Or using method calls directly, given that it's a pretty trivial query expression:
var highList = myArr.Cast<int>().Where(val => val > 5);
I think this will box each element, however. You could add your own Cast extension method to avoid that:
public static class RectangularArrayExtensions
{
public static IEnumerable<T> Cast<T>(this T[,] source)
{
foreach (T item in source)
{
yield return item;
}
}
}

Add one column of 2D array to listbox using AddRange

I have one 2D array:
string[,] table = new string[100,2];
and I want to add the table[,0] to a listbox, something like that
listbox1.Items.AddRange(table[,0]);
What is the trick to do that?
Edit: I want to know if it possible to do that using AddRange
For readability you can create extension method for an array.
public static class ArrayExtensions
{
public static T[] GetColumn<T>(this T[,] array, int columnNum)
{
var result = new T[array.GetLength(0)];
for (int i = 0; i < array.GetLength(0); i++)
{
result[i] = array[i, columnNum];
}
return result;
}
}
Now you can easily add ranges as slices from array. Note that you create a copy of elements from original array.
listbox1.Items.AddRange(table.GetColumn(0));

Passing one Dimension of a Two Dimensional Array in C#

I have moved from C to C#.
I have a function which accepts an array. I want to pass one dimension of a Two Dimensional array to this function.
C Code would be:-
void array_processing(int * param);
void main()
{
int Client_ID[3][50];
/* Some
Processing
which fills
this array */
array_processing(&Client_ID[1]);
}
Now, When I want to do same in C#, How can I pass this array?
Function defination will look like:-
private void array_processing(ref int[] param);
and Array would be declared as :-
int[,] Client_ID = new int[3,50];
Now How can I pass Client_ID[1] to the function array_processing()??
By doing array_processing ( ref Client_ID[1]) shouts as "Wrong Number of Indices"!
You can't really do that. C# is less outgoing about its arrays, and prevents you from doing C-like manipulations. This is a good thing.
You have various options:
Create a 1D array and copy your 2D row to it.
Use a jagged array - an array of arrays, which is more like what C lets you do.
Have an array_processing overload that takes a 2D array and a row number.
If you really want to access a 2D row as a 1D array, you should create a 'RowProxy' class that will implement the IList interface and let you access just one row:
class RowProxy<T>: IList<T>
{
public RowProxy(T[,] source, int row)
{
_source = source;
_row = row;
}
public T this[int col]
{
get { return _source[_row, col]; }
set { _source[_row, col] = value; }
}
private T[,] _source;
private int _row;
// Implement the rest of the IList interface
}
Use a lambda expression that will lose the array semantics, but is rather cool:
var ClientId = ...;
var row_5_accessor = (c=>ClientId[5, c]);
You can use row_5_accessor as a function, row_5_accessor(3) will give you ClientId[5, 3]
You can use a jagged array
// Initialize jagged array
int[][] clientID = new int[3][];
for (int i=0; i<clientId.Length; i++)
{
clientId[i] = new int[50];
}
array_processing(ref clientId[1]);
And your method:
private void array_processing(ref int[] subArray);
Just declare method
private void ParseArray(int[,] ar)
{
// Some work...
}
UDP: Code format
A primitive way would be:
var dimNumber = 1;
int[] oneDimension = new int[50];
for(var i=0; i<50; i++)
{
oneDimension[i] = Client_ID[dimNumber][i];
}
array_processing ( ref oneDimension);
I would suggest using Lambda expressions like in the way 5 of zmbq's answer.
You could declare you array as
int[][] Client_ID = new[] { new int[50], new int[50], new int[50] };
and then you can pass it to your array_processing function
array_processing(ref Clinet_ID[1]);
Sorry for miss of my pen.
Late to the conversation, but here is a jagged array example to do this:
string[][] rows = GetStringArray(values);
string[] row = rows[0];
You would set up your jagged array something like:
// rowCount from runtime data
stringArray = new string[rowCount][];
for (int index = 0; index < rowCount; index++)
{
// columnCount from runtime data
stringArray[index] = new string[columnCount];
for (int index2 = 0; index2 < columnCount; index2++)
{
// value from runtime data
stringArray[index][index2] = value;
}
}

C# arrays minimal value in specific range

Everybody!
How can I get minimal value of an int array in specific range in C#?
For example:
int[] array= new int{1,2,3,4,5,6,7,8,76,45};
And I want to get a minimal value between 3-rd and 8-th element.
Maybe it is possible to get via LINQ queries?
array.Skip(2).Take(5).Min();
I figure I may as well add my tuppence to this. As Jason objects to the fact that we're saying how many we're skipping rather than the end index, we can add a simple extension method:
public static IEnumerable<T> WithIndexBetween<T>(this IEnumerable<T> source,
int startInclusive, int endExclusive)
{
// The two values can be the same, yielding no results... but they must
// indicate a reasonable range
if (endExclusive < startInclusive)
{
throw new ArgumentOutOfRangeException("endExclusive");
}
return source.Skip(startInclusive).Take(endExclusive - startInclusive);
}
Then:
int min = array.WithIndexBetween(2, 7).Min();
Adjust the extension method name to taste. (Naming is hard, and I'm not going to spend ages coming up with a nice one here :)
int[] arr = {0,1,2,3,4,5,6,7,8};
int start = 3;
int end = 8;
int min = arr.Skip(start - 1).Take(end - start).Min();
int min = array.Where((value, index) => index >= 2 && index <= 7).Min();
EDIT
Actually, the approach above is quite inefficient, because it enumerates the whole sequence, even though we're not interested in items with an index higher than 7. A better solution would be to use TakeWhile:
int min = array.TakeWhile((value, index) => index <= 7).Skip(2).Min();
Unfortunately it's not very readable... The best option to make it nicer is probably to create a custom extension method, as shown in Jon's answer.
Just to add another option:
int start = 3;
int end = 8;
var min = Enumerable.Range(start - 1,end - start).Select(idx => array[idx]).Min();
AFAIK, this is "theorically" faster if you have to take a range near to the end of the one, and your array is really really long.
That's because (again AFAIK) Skip() doesn't take into account that is an array (i.e. can be accessed randomly in O(1)) and enumerates it anyway.
array.Skip(3).Take(4).Min();
Personally, I'd prefer this:
public static class ArrayExtensions {
public static bool ArrayAndIndexesAreValid(
T[] array,
int startInclusive,
int endExclusive
) {
return array != null &&
array.Length > 0 &&
startInclusive >= 0 && startInclusive < array.Length &&
endExclusive >= 1 && endExclusive <= array.Length &&
startInclusive < endExclusive;
}
public static IEnumerable<T> Slice<T>(
this T[] array,
int startInclusive,
int endExclusive
) {
Contract.Requires<ArgumentException>(ArrayAndIndexesAreValid(
array,
startInclusive,
endExclusive)
);
for (int index = startInclusive; index < endExclusive; index++) {
yield return array[index];
}
}
public static T MinimumInIndexRange<T>(
this T[] array,
int startInclusive,
int endExclusive
) where T : IComparable {
Contract.Requires<ArgumentException>(ArrayAndIndexesAreValid(
array,
startInclusive,
endExclusive)
);
return array.Slice(startInclusive, endExclusive).Min();
}
public static T MaximumInIndexRange<T>(
this T[] array,
int startInclusive,
int endExclusive
) where T : IComparable {
Contract.Requires<ArgumentException>(ArrayAndIndexesAreValid(
array,
startInclusive,
endExclusive)
);
return array.Slice(startInclusive, endExclusive).Max();
}
}

Initialize a Jagged Array the LINQ Way

I have a 2-dimensional jagged array (though it's always rectangular), which I initialize using the traditional loop:
var myArr = new double[rowCount][];
for (int i = 0; i < rowCount; i++) {
myArr[i] = new double[colCount];
}
I thought maybe some LINQ function would give me an elegant way to do this in one statement. However, the closest I can come up with is this:
double[][] myArr = Enumerable.Repeat(new double[colCount], rowCount).ToArray();
The problem is that it seems to be creating a single double[colCount] and assigning references to that intsead of allocating a new array for each row. Is there a way to do this without getting too cryptic?
double[][] myArr = Enumerable
.Range(0, rowCount)
.Select(i => new double[colCount])
.ToArray();
What you have won't work as the new occurs before the call to Repeat. You need something that also repeats the creation of the array. This can be achieved using the Enumerable.Range method to generate a range and then performing a Select operation that maps each element of the range to a new array instance (as in Amy B's answer).
However, I think that you are trying to use LINQ where it isn't really appropriate to do so in this case. What you had prior to the LINQ solution is just fine. Of course, if you wanted a LINQ-style approach similar to Enumerable.Repeat, you could write your own extension method that generates a new item, such as:
public static IEnumerable<TResult> Repeat<TResult>(
Func<TResult> generator,
int count)
{
for (int i = 0; i < count; i++)
{
yield return generator();
}
}
Then you can call it as follows:
var result = Repeat(()=>new double[rowCount], columnCount).ToArray();
The behavior is correct - Repeat() returns a sequence that contains the supplied object multiple times. You can do the following trick.
double[][] myArr = Enumerable
.Repeat(0, rowCount)
.Select(i => new double[colCount])
.ToArray();
You can't do that with the Repeat method : the element parameter is only evaluated once, so indeed it always repeats the same instance. Instead, you could create a method to do what you want, which would take a lambda instead of a value :
public static IEnumerable<T> Sequence<T>(Func<T> generator, int count)
{
for (int i = 0; i < count; i++)
{
yield return generator();
}
}
...
var myArr = Sequence(() => new double[colCount], rowCount).ToArray();
I just wrote this function...
public static T[][] GetMatrix<T>(int m, int n)
{
var v = new T[m][];
for(int i=0;i<m; ++i) v[i] = new T[n];
return v;
}
Seems to work.
Usage:
float[][] vertices = GetMatrix<float>(8, 3);
What about
var myArr = new double[rowCount, colCount];
or
double myArr = new double[rowCount, colCount];
Reference: http://msdn.microsoft.com/en-us/library/aa691346(v=vs.71).aspx

Categories

Resources