Span and two dimensional Arrays - c#

Is it possible to use the new System.Memory Span struct with two dimensional arrays of data?
double[,] testMulti =
{
{ 1, 2, 3, 4 },
{ 5, 6, 7, 8 },
{ 9, 9.5f, 10, 11 },
{ 12, 13, 14.3f, 15 }
};
double[] testArray = { 1, 2, 3, 4 };
string testString = "Hellow world";
testMulti.AsSpan(); // Compile error
testArray.AsSpan();
testString.AsSpan();
Whilst testArray and testString have a AsSpan extension, no such extension exists for testMulti.
Is the design of Span limited to working with single dimensional arrays of data?
I've not found an obvious way of working with the testMulti array using Span.

You can create a Span with unmanaged memory. This will allow you to Slice and Dice indiscriminately.
unsafe
{
Span<T> something = new Span<T>(pointerToarray, someLength);
}
Full Demo
unsafe public static void Main(string[] args)
{
double[,] doubles = {
{ 1, 2, 3, 4 },
{ 5, 6, 7, 8 },
{ 9, 9.5f, 10, 11 },
{ 12, 13, 14.3f, 15 }
};
var length = doubles.GetLength(0) * doubles.GetLength(1);
fixed (double* p = doubles)
{
var span = new Span<double>(p, length);
var slice = span.Slice(6, 5);
foreach (var item in slice)
Console.WriteLine(item);
}
}
Output
7
8
9
9.5
10
Other options would be to reallocate to a single dimension array, cop the penalty and do not Pass-Go
BlockCopy
or p/invoke memcpy directly and use unsafe and pointers
Cast<T> eg multiDimensionalArrayData.Cast<byte>().ToArray()
The first 2 will be more performant for large arrays.

You can use the new MemoryMarshal.CreateSpan and MemoryMarshal.GetArrayDataReference for this.
public static Span<T> AsSpan<T>(this Array array)
{
return MemoryMarshal.CreateSpan(ref Unsafe.As<byte, T>(ref MemoryMarshal.GetArrayDataReference(array)), array.Length);
}
dotnetfiddle
This works on all dimensions of arrays. If you want generic type inference to work, you will need separate functions for every rank (level of dimension), such as AsSpan<T>(this T[,] array) and AsSpan<T>(this T[,,] array).

As John Wu already mentioned spans are one dimensional.
You could of course implement a 2D span yourself, but Microsoft already did that for us.
Have a look into the docs here.
You can find the addressing nuget package here.
The package also provides a Memory2D.
var arr = new int[,] { {1,2,3},{2,2,3},{3,2,3} };
var spn = arr.AsSapn2D();
// Now use it similar to a normal span
// The access is of course a bit different since we are using a 2D data structure.
Console.WriteLine(spn[0..2,..]);

All spans are one-dimensional because memory is one-dimensional.
You can of course map all manner of structures onto one-dimensional memory, but the Span class won't do it for you. But you could easily write something yourself, for example:
public class Span2D<T> where T : struct
{
protected readonly Span<T> _span;
protected readonly int _width;
protected readonly int _height;
public Span2D(int height, int width)
{
T[] array = new T[_height * _width];
_span = array.AsSpan();
}
public T this[int row, int column]
{
get
{
return _span[row * _height + column];
}
set
{
_span[row * _height + column] = value;
}
}
}
The tricky part is implementing Slice(), since the semantics are sort of ambiguous for a two-dimensional structure. You can probably only slice this sort of structure by one of the dimensions, since slicing it by the other dimension would result in memory that is not contiguous.

As #saruman I don't believe it's possible.
You will need to get a new single dimension array first using techniques shown in Fast way to convert a two dimensional array to a List ( one dimensional ) or Convert 2 dimensional array, for example.

Perhaps there's more success to be had working with a jagged array instead of a multidimensional array.
double[][] testMulti =
{
new double[] { 1, 2, 3, 4 },
new double[] { 5, 6, 7, 8 },
new double[] { 9, 9.5f, 10, 11 },
new double[] { 12, 13, 14.3f, 15 }
};
Span<double[]> span = testMulti.AsSpan(2, 1);
Span<double> slice = span[0].AsSpan(1, 2);
foreach (double d in slice)
Console.WriteLine(d);
slice[0] = 10.5f;
Console.Write(string.Join(", ", testMulti[2]));
Console.ReadLine();
OUTPUT
9.5
10
9, 10.5, 10, 11

Related

How to initialize a multidimensional array

My problem is I want to initialize a multidimensional array declared like this:
int[][][] my3DArray;
However, the following code gives me an error on [sizeY][sizeZ] saying it expected ',' or ']'.
void Set3DArraySize(int sizeX, int sizeY, int sizeZ)
{
my3DArray = new int[sizeX][sizeY][sizeZ];
}
When i declare the array like this though:
int[,,] my3DArray;
I am able to initialize it without any problems by doing it like this:
my3DArray = new int[sizeX,sizeY,sizeZ];
But then the problem becomes that if I try to get the length of one of the arrays I can't do for example my3DArray[x,y].Length and am instead forced to pass all of the indexes together my3DArray[x,y,z].
So, is there any way I can initialize the array with it being declared as int[][][] my3DArray;? Or will I have to store the sizes of the arrays elsewhere and use it like this int[,,] my3DArray;?
You can do:
new int[][][] myArray = new int[][][]
{
new int[][]
{
new int[]
{
// Your numbers
}
}
}
myArray[0].Length
myArray[0][0].Length
myArray[0][0][0].Length
Works fine
int[][] is a jaggad array, which means that every array can be in a different size.
This is why you can initialize it that way:
int[][] arr2D= new int[3][];
arr2D[0] = new int[0];
arr2D[1] = new int[1];
arr2D[2] = new int[2];
which will create a 2d array that looks like this:
_
_ _
_ _ _
The following is an example to create 3d jaggad array (with different sizes for each dimension- 5 rows, 3 columns and 6 depth):
int[][][] arr3D = new int[5][][];
for (int col = 0; col < arr3D.Length; col++)
{
arr3D[col] = new int[3][];
for (int depth = 0; depth < arr3D[col].Length; depth++)
{
arr3D[col][depth] = new int[6];
}
}
In order to get the dimension size in jaggad array, you can simply get the lenth of the array, but keep in mind that if the array is actually jagged, you will have different sizes for different arrays. if you initialize all of the arrays in a specific dimension with the same value, than you can check either of them, it will be the same.
int[,] is a multi dimensional array that every dimension have a fixed size.
To create a multi dimensional:
int[,] arr2D = new int[3,4];
which will create a 2d array looking like this:
_ _ _ _
_ _ _ _
_ _ _ _
In multi dimensional array you can't change the length of a specific row or column.
In most cases you will probably prefer a multi dimensional array.
In order to get the size of a specific dimension in a multi dimensional array, you can use the following method:
int rows = arr22.GetLength(0); int cols = arr22.GetLength(1); int depth = arr22.GetLength(2);
The input is the dimension you want the size of.
You can't declare a jagged array in one line like this: new int[sizeX][sizeY][sizeZ]; as you really have three levels of nested arrays. You need to initialize them at each level.
This is what that would look like:
void Set3DArraySize(int sizeX, int sizeY, int sizeZ)
{
my3DArray = new int[sizeX][][];
for (var x = 0; x < sizeX; x++)
{
my3DArray[x] = new int[sizeY][];
for (var y = 0; y < sizeY; y++)
{
my3DArray[x][y] = new int[sizeZ];
}
}
}
Now, if you do want to initialize a multidimensional array, you can do this:
int[,,] z =
{
{ { 1, 2, }, { 1, 2, }, { 1, 2, }, },
{ { 1, 5, }, { 1, 5, }, { 2, 8, }, },
{ { 1, 5, }, { 1, 5, }, { 2, 8, }, },
{ { 1, 5, }, { 1, 5, }, { 2, 8, }, },
};
And then, to get the dimensions, you can do this:
Console.WriteLine(z.GetLength(0));
Console.WriteLine(z.GetLength(1));
Console.WriteLine(z.GetLength(2));
That gives me:
4
3
2
It's important to note that with a jagged array each nested array can be of different length, but with a multidimensional array then each dimension must be uniform.
For example, a jagged array could look like this:
int[][] y = new int[][]
{
new [] { 1, 2, },
new [] { 1, 2, 3, },
new [] { 1, },
};
And a multidimensional array like this:
int[,] y =
{
{ 1, 2, 3, },
{ 4, 5, 3, },
{ 1, 6, 3, },
{ 1, 7, 8, },
};
I could not do this:
//illegal!!!
int[,] y =
{
{ 1, 2, 3, },
{ 4, 5, 3, 7, },
{ 1, 6, },
{ 1, 7, 8, },
};
First,
int[][][]
is a jagged array, or an array of arrays of arrays. Where as,
int [,,]
is a multi-dimensioinal array. A single array with many dimensions.
While multi-dimensional arrays are easier to instantiate and will have fixed dimensions on every axis, historically, the CLR has been optimized for the vastly more common case of single dimensional arrays, as used in jagged arrays. For large sizes, you may experience unexpected performance issues.
You can still get the dimensions of a multi-dimensional array by using the GetLength method, and specifying the dimension you are interested in but, its a little clunky.
The number of dimensions can be retrieved from the Rank property.
You may prefer a jagged array and instantiating one axis at a time.
To instantiate jagged arrays, see this Initializing jagged arrays.
void Set3DArraySize(int sizeX, int sizeY, int sizeZ)
{
my3DArray = Enumerable.Repeat(Enumerable.Repeat(new int[sizeZ], sizeY).ToArray(),sizeX).ToArray();
}

Return the sorted array [duplicate]

This question already has answers here:
Fastest way to check if an array is sorted
(9 answers)
Closed 5 years ago.
Imagine i get two arrays as input, one of which is already sorted. I want to create a method which checks which array that is sorted and then returns it. Im not really sure how to do this
class Program
{
public double[] a = new double[] { 1, 3, 4, 8, 21, 38 };
public double[] b = new double[] { 1, 7, 19, 3, 2, 24 };
public void CheckSorting()
{
if (/* if a is sorted */)
{
return a;
}
else { /* This should be OK because if A isnt sorted then b MUST be sorted since of the arrays are always sorted in my input */
return b;
}
}
static void Main(string[] args)
{
Program checkSorting = new Program();
checkSorting.CheckSorting();
}
}
In this case, as you can see the array A should be returned as the sorted one
just.... loop over one of the arrays in a forwards direction; if the value ever goes down, that array isn't sorted
for(int i = 1 ; i < a.Length ; i++)
{
if(a[i] < a[i-1]) return b;
}
return a;
private double[] ArraySort()
{
double[] a = new double[] { 1, 3, 4, 8, 21, 38 };
double[] b = new double[] { 1, 7, 19, 3, 2, 24 };
var isOrderedAscending = a.SequenceEqual(a.OrderBy(x => x));
if (isOrderedAscending)
return a;
else
return b;
}
this method might help you,
but what has to be achieved if both or not ordered ?

C# Elements in Dimension

I want to find out number of elements in provided dimension using C#:
int [][] arr = new int [3][];
int elements_dim0 = arr.GetLength(0); // Returns 3, which is the size of dimension. I want it to return the actual count of elements in provided dimension.
int [][] is not a multidimensional array - its jagged array (i.e. it's array of arrays). If you want to get length of array at some index, you should use
arr[0].Length
But make sure that you have initialized array element before getting it's length (otherwise you will get NullReferenceException). E.g.:
arr[0] = new int[] { 1, 2, 3 };
arr[1] = new int[] { 4, 5 };
You can also initialize jagged array with array initializer syntax:
int[][] arr = { new[] { 1, 2, 3 }, new[] { 4, 5 }, new[] { 6 } };
Note that multidimensional arrays are defined as int [,]. And you can use GetLowerBound(int dimension) (usually it's zero) and GetUpperBound(int dimension) to get bounds of each array dimension. E.g. creating multidimensional array of size 2 x 4:
int[,] grid = { { 1, 2, 3, 4 }, { 5, 6, 7, 8 } };
grid.GetUpperBound(0); // 1
grid.GetUpperBound(1); // 3
Further readings: Jagged Arrays and Multidimensional Arrays

How do I pick values from an array without having repeating values in C# [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 8 years ago.
Improve this question
I am using C# and I have an array that stores 20 integers.
I have 3 variables and I would like to assign them all to randomly-picked integers from the array, but I have to make it so that the values picked from the array are not the same.
Is there any way to do this other than by using a lot of if statements?
This answer is based on ThariqNugrohotomo's suggestion regarding selecting three distinct values from a shuffled array. I implemented a version of Fisher-Yates Shuffle algorithm, which is based on DotNetPerls example. The reason three distinct values are selected after the shuffle is performed is due to the fact that the source array may have repeating values. If we simply shuffle them, then there's a possibility of duplicates.
using System;
using System.Linq;
namespace ShuffleAndTakeUnique
{
public class Program
{
static Random _random = new Random();
static void Main(string[] args)
{
int[] array = { 3, 4, 6, 2, 5, 11, 12, 20, 19, 18, 17, 15, 16, 1, 7, 8, 9, 10, 13, 14 };
var values = Shuffle<int>(array).Distinct().Take(3).ToArray();
foreach(var val in values)
{
Console.WriteLine(val);
}
}
public static T[] Shuffle<T>(T[] source)
{
T[] array = new T[source.Length];
Array.Copy(source, array, source.Length);
var random = _random;
for (int i = array.Length; i > 1; i--)
{
int j = random.Next(i);
T tmp = array[j];
array[j] = array[i - 1];
array[i - 1] = tmp;
}
return array;
}
}
}
Below are older ideas:
Here's a quick and dirty Console Application that stores three unique int values in a List<int>. You may then assign the values from that list to your variables. The list serves as a way to ensure uniqueness of the values. This is just an example, so obviously alter it to your needs and clean it up.
using System;
using System.Collections.Generic;
namespace App
{
class Program
{
static Random random = new Random();
static int[] array = { 3, 4, 6, 2, 5, 11, 12, 20, 19, 18, 17, 15, 16, 1, 7, 8, 9, 10, 13, 14 };
static List<int> results = new List<int>();
static void Main(string[] args)
{
while (results.Count < 3)
{
int num = array[random.Next(array.Length)];
if (!results.Contains(num))
{
results.Add(num);
}
}
foreach(var result in results)
{
Console.WriteLine(result);
}
}
}
}
EDIT:
Here's an example that uses a generic method that will give you back an array of specified length (up to the maximum of the original array) that contains unique values from the original array:
using System;
using System.Collections.Generic;
using System.Linq;
namespace GetUniqueValues
{
class Program
{
static void Main(string[] args)
{
int[] array1 = { 3, 4, 6, 2, 5, 11, 12, 20, 19, 18, 17, 15, 16, 1, 7, 8, 9, 10, 13, 14 };
var values1 = GetUniqueValues<int>(array1, 3);
foreach (var val in values1)
{
Console.WriteLine(val);
}
string[] array2 = { "apple", "orange", "cherry", "melon", "grapefruit", "grapes", "peach", "watermelon" };
var values2 = GetUniqueValues<string>(array2, 4);
foreach (var val in values2)
{
Console.WriteLine(val);
}
}
public static T[] GetUniqueValues<T>(T[] array, int valuesCount)
{
var values = new List<T>();
if (array != null && array.Length > 0 && valuesCount > 0)
{
var distinctCount = array.Distinct().Count();
if (valuesCount > distinctCount)
{
valuesCount = distinctCount;
}
var random = new Random();
while(values.Count < valuesCount)
{
T val = array[random.Next(array.Length)];
if (!values.Contains(val))
{
values.Add(val);
}
}
}
return values.ToArray();
}
}
}
Note that I make sure that the number of distinct values in the array is not less than the requested number of values. Otherwise, we'd be stuck in an infinite loop. If you pass an empty array or a count less than one, it will return an empty array. I prefer that over null... but once again, it's up to you.
Another way is to pass a copy of the original array as a List<T> and remove any occurrence of a value, once it's picked. That way, there is no way you can ever choose it again. Here's a quick, untested draft (I didn't test this at all), but you'll get the idea:
while(values.Count < valuesCount && list.Count > 0)
{
T val = list[random.Next(list.Count)];
values.Add(val);
list.RemoveAll(val);
}

Handling of array operations in C sharp

I have been programming with Matlab for a couple of years. It handles operations on matrices and arrays quite easily.
Now, I am programming in C# and after reading for a while on sites such as http://msdn.microsoft.com/en-us/library/2s05feca.aspx and various other tutorial websites, I still have some questions.
In Matlab, something like this (written in a pseudo C# syntax) would work:
W[1][][] = new double[][]{{10,20,30},{40,50,60},};
where W is a 3 dimensional jagged array. The idea is that since the first dimension is defined (by 1 in this case), the assignation operation "understand" that the content of the 2 dimensional array provided is set to fill the two remainder dimensions of W. Then, how to get the same result or behaviour in C#?
Imagine the first dimension of W[][][] is a number associated with a city; the second, the age of every people living there and the third, their weight. Now lets have a portion of code that create a "calculation[][]" array containing ages and weights values. I want to assign the content of this array to W[1][][]. That is what I have failed to implement.
My objective is to do the equivalent of multiplication of matrices (and other relevant operations on matrices) using C#.
I read and read again a couple of explanations (can't list them all here) but it does not add up in my head, so I guess if someone could explain (again) how to manipulate multidimensional arrays in C#, it will help me understand how it works.
Thanks
This isn't a 3 dimensional array. This is just an array of an array.
I'm not really sure what you try to do.
Anyway, If I got u right u want to do something like this:
Ok, so if you need this for your example then I would recommend you a struct in order to do this easier.
If you want to understand Multidimensional Arrays then you should reed the following:
You defined your 'Multidimensional Array' like this:
double[][][] array;
That's not a 'Multidimensional Array'. This is an array (list) of an array of an array.
A real 'Multidimensional Array' is defined this (3 dimensions):
double[,,] array;
That's a difference :D
if u use the 'real Multidimensional Array' then u can do the above like this;
private static void Main(string[] args)
{
var raw = new double[,,]
{
{
{1, 2},
{3, 4}
},
{
{5, 6},
{7, 8}
}
};
Console.WriteLine(raw[0, 0, 0]); //1
Console.WriteLine(raw[1, 1, 0]); //7
Console.ReadKey();
}
And this would be the code for the array of an array of an array
var raw = new double[][][]
{
new double[][]
{
new double[]
{
1,
3
},
new double[]
{
2,
4
}
},
new double[][]
{
new double[]
{
5,
7
},
new double[]
{
6,
8
}
}
};
Console.WriteLine(raw[0][0][0]); //1
Console.WriteLine(raw[1][1][0]); //6
Console.ReadKey();
In your case (if you don't want to use a struct) than this array would be the better way!
A struct for your case would look like this:
private static void Main(string[] args)
{
var raw = new SampleDataStruct[2]
{
new SampleDataStruct
{
CityName = "New York", AgeWeight = new AgeWeightStruct[3]
{
new AgeWeightStruct{Age = 50,Weigth = 70},
new AgeWeightStruct{Age = 40,Weigth = 75},
new AgeWeightStruct{Age = 30,Weigth = 65}
}
},
new SampleDataStruct
{
CityName = "Berlin", AgeWeight = new AgeWeightStruct[3]
{
new AgeWeightStruct{Age = 50,Weigth = 65},
new AgeWeightStruct{Age = 40,Weigth = 60},
new AgeWeightStruct{Age = 30,Weigth = 55}
}
}
};
Console.WriteLine(raw.Where(st => st.CityName == "Berlin").ElementAtOrDefault(0).AgeWeight.Where(aw => aw.Age == 40).ElementAtOrDefault(0).Weigth); //Berlin -> Age = 40 -> Display Weight (60)
Console.WriteLine(raw.Where(st => st.CityName == "New York").ElementAtOrDefault(0).AgeWeight.Where(aw => aw.Age == 30).ElementAtOrDefault(0).Weigth); //New York -> Age = 30 -> Display Weight (65)
Console.ReadKey();
}
}
public struct SampleDataStruct
{
public string CityName;
public AgeWeightStruct[] AgeWeight;
}
public struct AgeWeightStruct
{
public int Age;
public int Weigth;
}
You can do it so:
Int32 firstDimensionSize = 3;
double[][][] matrix3D = new double[firstDimensionSize ][][];
matrix3D[1]= new double[][]
{
new double[]{10,20,30},
new double[]{40,50,60},
};
Because matrix3D is an array of arrays of arrays. Each its element is double[][] - 2D jagged array. Just don't forget that matrix3D[0] and matrix3D[2] will be uninitialized - null.
var W = new double[][][]
{
new double[][]{
new double[] {1,2,3}, new double[] {4,5,6}
},
new double[][]{
new double[] {7,8,9}, new double[] {10,11,12}
}
};
Alternatively, you can use a double[,,] if the dimensions are the same:
var W = new double[,,]
{
{
{1,2,3}, {4,5,6}
},
{
{7,8,9}, {10,11,12}
}
};

Categories

Resources