How to get a dimension (slice) from a multidimensional array - c#

I'm trying to figure out how to get a single dimension from a multidimensional array (for the sake of argument, let's say it's 2D), I have a multidimensional array:
double[,] d = new double[,] { { 1, 2, 3, 4, 5 }, { 5, 4, 3, 2, 1 } };
If it was a jagged array, I would simply call d[0] and that would give me an array of {1, 2, 3, 4, 5}, is there a way I can achieve the same with a 2D array?

No. You could of course write a wrapper class that represents a slice, and has an indexer internally - but nothing inbuilt. The other approach would be to write a method that makes a copy of a slice and hands back a vector - it depends whether you want a copy or not.
using System;
static class ArraySliceExt
{
public static ArraySlice2D<T> Slice<T>(this T[,] arr, int firstDimension)
{
return new ArraySlice2D<T>(arr, firstDimension);
}
}
class ArraySlice2D<T>
{
private readonly T[,] arr;
private readonly int firstDimension;
private readonly int length;
public int Length { get { return length; } }
public ArraySlice2D(T[,] arr, int firstDimension)
{
this.arr = arr;
this.firstDimension = firstDimension;
this.length = arr.GetUpperBound(1) + 1;
}
public T this[int index]
{
get { return arr[firstDimension, index]; }
set { arr[firstDimension, index] = value; }
}
}
public static class Program
{
static void Main()
{
double[,] d = new double[,] { { 1, 2, 3, 4, 5 }, { 5, 4, 3, 2, 1 } };
var slice = d.Slice(0);
for (int i = 0; i < slice.Length; i++)
{
Console.WriteLine(slice[i]);
}
}
}

Improved version of that answer:
public static IEnumerable<T> SliceRow<T>(this T[,] array, int row)
{
for (var i = array.GetLowerBound(1); i <= array.GetUpperBound(1); i++)
{
yield return array[row, i];
}
}
public static IEnumerable<T> SliceColumn<T>(this T[,] array, int column)
{
for (var i = array.GetLowerBound(0); i <= array.GetUpperBound(0); i++)
{
yield return array[i, column];
}
}

Rectangular arrays are not built for this purpose. If you need that type of functionality, you should switch to a jagged array. It is pretty simple to write a function that will convert a rectangular array into a jagged one.
You could also simply rebuild that array by calling GetLength(int dimension) on the appropriate dimension, and then indexing it properly to retrieve each value. It would be cheaper than converting the entire array, but the cheapest option is to change it to use jagged arrays.

This should replicate the a[r] functionality of a jagged array:
T[] Slice<T>(T[,] a, int r) => Enumerable.Range(0, a.GetUpperBound(1) + 1).Select(i => a[r, i]).ToArray();

Related

Declare a List of fixed size array

I want to ensure that my List can contain only 2 elements array of int. I am currently have to declare a struct but I really don't want to declare many type if it is not really necessary. So I am wondering if I can declare a list of fixed size array.
static void Main(string[] args)
{
//I want to declare something like this
List<int[2]> list = new List<int[2]>();
list.Add(new int[2] { 1, 2 });
list.Add(new int[2] { 3, 4 });
//What I having to do(not really want because I have to declare struct)
List<TwoElement> list2 = new List<TwoElement>();
list2.Add(new TwoElement() { Element1 = 1, Element2 = 2 });
list2.Add(new TwoElement() { Element1 = 1, Element2 = 2 });
}
private struct TwoElement
{
public int Element1;
public int Element2;
}
It's not possible, as reference from this post, in short, int[2] is not a Type, therefore no way to limit it without a struct, model or tuple.
I will prefer using tuple in this case, since it's pretty simple with lambda
List<(int, int)> list = new List<(int, int)>();
list.Add((1, 1));
list.Add((2, 3));
Here's an idea of a fixed length array. If the length was more than 2, then I'd probably have a private int[] theArray member. But, at two, it probably makes sense to have a _first and a _second member the way I show. The System.Array class has a lot of members - you get to implement the ones you care about (I put all the Properties in (either as a property or as a const)).
In any case, it gives you an idea of a possible solution:
public class ArrayOf2Int : IEnumerable<int>
{
private readonly int _first;
private readonly int _second;
//I had the urge to make this a Lazy<object> - but it's an object, who cares
//If you implement this with an array of int (int[]) instead of two ints, delegate this to the SyncRoot of the array
public object SyncRoot { get; } = new object();
public const int Length = 2;
public const long LongLength = 2;
public const int Rank = 1;
public const bool IsFixedSize = true;
public const bool IsSynchronized = false;
public ArrayOf2Int(int first, int second)
{
_first = first;
_second = second;
}
public int this[int i]
{
get
{
if (i < 0 || i > 1)
{
throw new ArgumentOutOfRangeException(nameof(i), "Index out of range");
}
return i == 0 ? _first : _second;
}
}
public IEnumerator<int> GetEnumerator()
{
yield return _first;
yield return _second;
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}

Sort 2D array in C#

I was trying to compare a 2D array in C# using IComparer but not able to compile the code from my point of view in sort method ab is assumed to be a jagad array instead of a normal array .Does any one know how to solve that
int[,] ab = new int[3, 4]
{
{ 1, 2, 3, 4 },
{ 5, 6, 7, 8 },
{ 2, 3, 4, 5 }
};
Array.Sort<int[]>(ab, new ComparerTwoDArray());
foreach (var i in ab)
{
Console.WriteLine(i);
}
class ComparerTwoDArray : IComparer<int[]>
{
int ix;
public int Compare(int[] x, int[] y)
{
return x[0].CompareTo(y[0]);
}
}
You are not using the proper method: https://msdn.microsoft.com/en-us/library/system.array.sort%28v=vs.110%29.aspx
Array.Sort Method: Sorts the elements in a one-dimensional array.
You could use List<List<int>> and then use its Sort LINQ extension, like:
list.Sort((x,y) => x[0].CompareTo(y[0]));
Unfortunately a multi-dimensional array is a quite static beast. You can easily access single elements within it by providing the n-dimensional coordinates (eg. array[2,8,4] in a 3d array), but you can't access any whole areas (like rows, columns, rectangles, etc.).
If you really have the need to do such a kind of re-sorting you shouldn't save your data within a multi-dimensional array. Instead put it into a jagged array or a list of lists or even a IReadOnlyDictionary<int, IReadOnlyDictionary<int, IReadOnlyDictionary<int, int>>> for a 4 dimensions sparse matrix. In that case you could quite easily write a comparer for each dimension as you like.
In your case you just need a something like List<IReadOnlyList<int>> and a IComparer<IReadOnlyList<T>> which could possibly be implemented like this:
public class ListComparer<T> : IComparer<IReadOnlyList<T>>
{
public static readonly IComparer<IReadOnlyList<T>> Default = new ListComparer<T>();
private readonly bool _checkCount;
private readonly int _numberOfElementsToCompare;
private readonly IComparer<T> _elementComparer;
public ListComparer()
: this(true, 1, Comparer<T>.Default)
{
}
public ListComparer(
bool checkCount,
int numberOfElementsToCompare,
IComparer<T> elementComparer)
{
_checkCount = checkCount;
_numberOfElementsToCompare = numberOfElementsToCompare;
_elementComparer = elementComparer
?? throw new ArgumentNullException(nameof(elementComparer));
}
public int Compare(IReadOnlyList<T> x, IReadOnlyList<T> y)
{
if (ReferenceEquals(x, y))
return 0;
if (ReferenceEquals(x, null))
return -1;
if (ReferenceEquals(y, null))
return 1;
if (_checkCount)
{
var diff = x.Count.CompareTo(y.Count);
if (diff != 0)
return diff;
}
return x.Take(_numberOfElementsToCompare)
.Zip(y, (i, j) => _elementComparer.Compare(i, j))
.SkipWhile(value => value == 0)
.FirstOrDefault();
}
}
And would be used:
var matrix = new List<IReadOnlyList<int>>
{
{ new List<int> { 1, 2, 3, 4 } },
{ new List<int> { 5, 6, 7, 8 } },
{ new List<int> { 2, 3, 4, 5 } }
};
matrix.Sort(ListComparer<int>.Default);
foreach (var item in matrix)
{
Console.WriteLine(String.Join(", ", item));
}

C# - Nestable, bounded arrays

I'm porting a game written in Pascal (compiled in 16 bit) to C# (so it will run on machines newer than XP). From what I've gathered, in Pascal, it's possible to type define in the type section of a unit/program through syntax like this:
type
BaseArrayPtr = ^BaseArray;
BaseArray = array [1 .. 5, 1 .. 5] of Integer;
SubArray = array [0 .. 3] of BaseArray;
I also gathered that, unfortunately, it is impossible to type define in C#. However, I'm trying for a workaround. So far, this is what I have:
BoundedArray.cs:
using System;
using System.Collections;
namespace test
{
abstract class BoundedArray<T>
{
public BoundedArray()
{
m_data = null;
}
public T this[params int[] index]
{
get
{
if (index.Length != m_data.Rank)
throw new IndexOutOfRangeException();
return (T) m_data.GetValue(index);
}
set
{
if (index.Length != m_data.Rank)
throw new IndexOutOfRangeException();
m_data.SetValue(value, index);
}
}
protected void SetAttributes(int[] lowerBounds, int[] lengths)
{
if (lengths.Length != lowerBounds.Length)
throw new ArgumentException();
m_lowerBounds = lowerBounds;
m_lengths = lengths;
m_data = Array.CreateInstance(typeof(T), m_lengths, m_lowerBounds);
m_data.Initialize(); // Should (but doesn't) initialize every element in m_data
}
Array m_data;
int[] m_lengths;
int[] m_lowerBounds;
}
}
test.cs:
using System;
namespace test
{
class Program
{
public static int[] ints(params int[] values)
{
return values;
}
class BaseArray : BoundedArray<int>
{
public BaseArray()
{
SetAttributes(ints(2, 2), ints(1, 2));
}
}
class SubArray : BoundedArray<BaseArray>
{
public SubArray()
{
SetAttributes(ints(4), ints(2));
}
}
static void Main(string[] args)
{
SubArray subArray = new SubArray();
Console.Read();
}
}
}
I've checked baseArray, and the default values of m_data are zeroes, since they are ints. However, in subArray, the default values of m_data are null - the BaseArray instances inside the array in subArray haven't been initialized for some reason. How do I get the default constructor to run?
EDIT: The real question at the moment is why doesn't m_data.Initialize(); in the SetAttributes method initialize all elements in m_data? The documentation on MSDN seems to indicate that it should...
EDIT:
So I believe that problem is that System.Array.Initialize only works on value-types. Since classes are references types in C#, System.Array.Initialize doesn't do anything. So I have to find a way to initialize a reference-type array of variable dimensions, lengths, and lower bounds.
Well I have done some changes that when you want to create an instance of a SubArray you should pass BaseArray as source of data to be initialize.
As i understood you want to set the values from BaseArray to SubArray.
Here is my work:
BoundedArray.cs
abstract class BoundedArray<T>
{
public BoundedArray()
{
m_data = null;
}
public int[] Lengths;
public int[] LowerBounds;
public void CreateInstance()
{
if (Lengths.Length != LowerBounds.Length)
throw new Exception("Incorrect number of lengths or lower bounds.");
m_data = Array.CreateInstance(typeof(T), Lengths, LowerBounds);
}
public void CreateInstance(Array source)
{
if (Lengths.Length != LowerBounds.Length)
throw new Exception("Incorrect number of lengths or lower bounds.");
m_data = Array.CreateInstance(typeof(T), Lengths, LowerBounds);
/************************************************************************/
/* Now you should find the value of BaseArray and set it to m_data */
/************************************************************************/
}
public T this[params int[] index]
{
get
{
if (index.Length != m_data.Rank)
throw new IndexOutOfRangeException();
return (T)m_data.GetValue(index);
}
set
{
if (index.Length != m_data.Rank)
throw new IndexOutOfRangeException();
m_data.SetValue(value, index);
}
}
public Array GetData()
{
return m_data;
}
Array m_data;
}
Test.cs
class Program
{
public static int[] ints(params int[] values)
{
return values;
}
class BaseArray : BoundedArray<int>
{
public BaseArray()
{
Lengths = ints(1, 2);
LowerBounds = ints(2, 2);
CreateInstance();
}
}
class SubArray : BoundedArray<BaseArray>
{
public SubArray(BaseArray arr)
{
Lengths = ints(2);
LowerBounds = ints(4);
CreateInstance(arr.GetData());
}
}
static void Main(string[] args)
{
BaseArray baseArray = new BaseArray();
SubArray subArray = new SubArray(baseArray);
Console.Read();
}
}
You have a singe-dimensional array SubArray which holds BaseArray objects which are two-dimensional arrays of intergers. In place of Pascal type, you can define a custom C# class which would override the indexer operator to give you exactly the same behavior.
EDITED
So, in Pascal you have this:
type
BaseArrayPtr = ^BaseArray;
BaseArray = array [1 .. 5, 1 .. 5] of Integer;
SubArray = array [0 .. 3] of BaseArray;
Maybe I misunderstood the question, but is the below not exactly the same, in C#?
public class BaseArray
{
int[,] m_array = new int[5, 5];
static void CheckBounds(int x, int y)
{
if (x < 1 || x > 5 || y < 1 || y > 5)
throw new IndexOutOfRangeException();
}
public int this[int x, int y]
{
get
{
CheckBounds(x, y);
return m_array[x-1, y-1];
}
set
{
CheckBounds(x, y);
m_array[x-1, y-1] = value;
}
}
}
public class SubArray
{
BaseArray[] m_array = new BaseArray[4];
public BaseArray this[int x]
{
get { return m_array[x]; }
set { m_array[x] = value; }
}
}
I've already answered my own question once, but I came up with a much better implementation of my answer.
Here's what this solution consists of:
SetAttributes must be run once, in the default constructor of a class based off of BoundedArray
During SetAttributes, I gather a jagged, two-dimensional array of all of the indices in the current BoundedArray subclass
I create instances of the template type by calling Activator.CreateInstance and assigning one per index
Other things to note:
Set attributes now takes a variable length array of int[]s instead of two int[]s. Previously, it was taking the lowerbounds and the lengths, but I realized it makes more sense to just take int[]s which are lower and upper bounds, and then use a LINQ query to check that there aren't any which aren't pairs
I created a static class called IntArray, which is used extensively by SetAttributes and in test.cs
I tried to throw as many useful errors as possible, since I'll probably end up using this code a lot
I have a feeling that Combinations(int[][] list1, int[] list2) is probably where the most improvement on my solution could be found. I'm open to suggestions on how to improve all of my code
So, without further ado, my complete solution:
BoundedArray.cs
using System;
using System.Linq;
using System.Collections.Generic;
namespace test
{
static class IntArray
{
public static int[] FromValues(params int[] values)
{
return values;
}
public static int[] Sequence(int from, int length)
{
if (from < 0 || length < 1)
throw new ArgumentException();
return Enumerable.Range(from, length).ToArray();
}
public static int[][] Combinations(int[] list1, int[] list2)
{
return Combinations(list1.Select(i => new int[] { i }).ToArray(), list2);
}
public static int[][] Combinations(int[][] list1, int[] list2)
{
List<List<int>> result = new List<List<int>>();
for (int i = 0; i < list1.Length; i++)
{
for (int j = 0; j < list2.Length; j++)
result.Add(((int[]) list1.GetValue(i)).Concat(new int[] { list2[j] }).ToList());
}
return result.Select(i => i.ToArray()).ToArray();
}
}
abstract class BoundedArray<T>
{
public BoundedArray()
{
m_data = null;
}
public Array Value
{
get { return m_data; }
}
public T this[params int[] index]
{
get
{
if (index.Length != m_data.Rank)
throw new IndexOutOfRangeException();
return (T) m_data.GetValue(index);
}
set
{
if (index.Length != m_data.Rank)
throw new IndexOutOfRangeException();
m_data.SetValue(value, index);
}
}
protected void SetAttributes(params int[][] values)
{
// Make sure all of the values are pairs
if (values.Where(i => i.Length != 2).ToArray().Length > 0)
throw new ArgumentException("Input arrays must be of length 2.");
int[] lowerBounds = values.Select(i => i[0]).ToArray();
int[] lengths = values.Select(i => i[1] - i[0] + 1).ToArray();
m_data = Array.CreateInstance(typeof(T), lengths, lowerBounds);
int[][] indices = (lowerBounds.Length != 1) ?
IntArray.Combinations(IntArray.Sequence(lowerBounds[0], lengths[0]), IntArray.Sequence(lowerBounds[1], lengths[1]))
: IntArray.Sequence(lowerBounds[0], lengths[0]).Select(i => new int[] { i }).ToArray();
for (int i = 2; i < lowerBounds.Length; i++)
indices = IntArray.Combinations(indices, IntArray.Sequence(lowerBounds[i], lengths[i]));
for (int i = 0; i < indices.Length; i++)
m_data.SetValue(Activator.CreateInstance(typeof(T)), indices[i]);
}
Array m_data;
}
}
test.cs
using System;
namespace test
{
class Program
{
// *** Examples of what you can do with BoundedArray ***
// Multi-dimensional, bounded base array
class BaseArray : BoundedArray<int>
{
public BaseArray()
{
SetAttributes(IntArray.FromValues(2, 3), IntArray.FromValues(2, 4));
}
}
// One-dimensional, bounded subclass array
class SubArray : BoundedArray<BaseArray>
{
public SubArray()
{
SetAttributes(IntArray.FromValues(4, 6));
}
}
static void Main(string[] args)
{
// Initializations used for testing purposes
BaseArray baseArray = new BaseArray();
SubArray subArray = new SubArray();
// Example of assignment
baseArray[3, 4] = 3;
subArray[4][2, 3] = 4;
subArray[4][2] = 3; // Weakness: compiles, but causes IndexOutOfRangeException
Console.Read();
}
}
}
Thougts?

how to declare a free length 2d array in c#

Good day,
Normally I create 2D array as follow :
string [,] arr = new string [9,4];
This is a 2D array with 9 rows and 4 columns.
I would like to ask, how to create 2D array with any length.
For example, that is not nessecary to set the row to 9, it can be any number, depends on the situation.
what about simple List<List<T>> ?
This is like a concept, you naturally can wrap up this in your custom class, so consumer of your API don't see these wiered nested declarations.
public class Matrix {
private mtx = new List<List<T>>();
public void Append(T value) {
.....
}
public void InsertAt(T value, int row, int column) {
....
}
}
For that you must be using a List<List<string>> instance. Now you can dynamically add anything you want, however this also has the disadvantage over the array format that you need to check for yourself if you have reached the maximum number of rows or columns.
This Matrix class is space (based on access pattern) and performance efficient:
class Matrix<T>
{
readonly Dictionary<int, Dictionary<int, T>> _rows = new Dictionary<int, Dictionary<int, T>>();
public T this[int i, int j]
{
get
{
var row = ExpandOrGet(j);
if (!row.ContainsKey(i)) row[i] = default(T);
UpdateSize(i, j);
return row[i];
}
set
{
ExpandOrGet(j);
_rows[j][i] = value;
UpdateSize(i, j);
}
}
void UpdateSize(int i, int j)
{
if (j > SizeRows) SizeRows = j;
if (i > SizeColums) SizeColums = i;
}
public int SizeRows { get; private set; }
public int SizeColums { get; private set; }
Dictionary<int, T> ExpandOrGet(int j)
{
Dictionary<int, T> result = null;
if (!_rows.ContainsKey(j))
{
result = new Dictionary<int, T>();
_rows[j] = result;
}
else result = _rows[j];
return result;
}
}
Although you can add further utilities to facilitate your workflow.

How do you Iterate a multidimesional array without knowing the number of dimensions and elements of the array being passed to you?

A SDK is returning me an array with multiple dimensions such as:
int[,,] theArray = new int[2,8,12];
I need to visit each element in the array and return the value and the position of the value. I need to do this without knowing the number of dimensions and elements of the array being passed in.
Use for loops:
for (int i=theArray.GetLowerBound(0);i<=theArray.GetUpperBound(0);++i)
{
for (int j=theArray.GetLowerBound(1);j<=theArray.GetUpperBound(1);++j)
{
for (int k=theArray.GetLowerBound(2);k<=theArray.GetUpperBound(2);++k)
{
// do work, using index theArray[i,j,k]
}
}
}
If you don't know the number of dimensions in advance, you can use Array.Rank to determine that.
Would something like this work for you? It recurses the ranks so you can use a foreach() and get an array containing the current item's indices.
class Program
{
static void Main(string[] args)
{
int[, ,] theArray = new int[2, 8, 12];
theArray[0, 0, 1] = 99;
theArray[0, 1, 0] = 199;
theArray[1, 0, 0] = 299;
Walker w = new Walker(theArray);
foreach (int i in w)
{
Console.WriteLine("Item[{0},{1},{2}] = {3}", w.Pos[0], w.Pos[1], w.Pos[2], i);
}
Console.ReadKey();
}
public class Walker : IEnumerable<int>
{
public Array Data { get; private set; }
public int[] Pos { get; private set; }
public Walker(Array array)
{
this.Data = array;
this.Pos = new int[array.Rank];
}
public IEnumerator<int> GetEnumerator()
{
return this.RecurseRank(0);
}
private IEnumerator<int> RecurseRank(int rank)
{
for (int i = this.Data.GetLowerBound(rank); i <= this.Data.GetUpperBound(rank); ++i)
{
this.Pos.SetValue(i, rank);
if (rank < this.Pos.Length - 1)
{
IEnumerator<int> e = this.RecurseRank(rank + 1);
while (e.MoveNext())
{
yield return e.Current;
}
}
else
{
yield return (int)this.Data.GetValue(this.Pos);
}
}
}
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
return this.RecurseRank(0);
}
}
}
I'm not sure I understand your question about "return the position[n,n,n]", but if you're trying to return more than one value from a method, there are a couple of ways to do it.
• Useoutor reference parameters (e.g.,Int) that get set to the returned values before returning from the method.
• Pass in an array, e.g., an array of three ints, the elements of which get set by the method before it returns.
• Return an array of values, e.g., an array of three ints.

Categories