C# - Nestable, bounded arrays - c#

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?

Related

How can I loop through n-dimensional sparse matrix (created by own class)?

I have two classes
class CSparseMatrix:
{
public int NumberOfDimensions { get; set;}
public int DefaultNumber { get; set; }
List<int> dimensionsRanges = new List<int>(); // that's specify dimension of ranges, f.e. {100, 100, 100, 120..}
List<CSparseCell> cells = new List<CSparseCell>(); // contains only values different from default for this matrix
}
class CSparseCell {
public int Value { get; set; }
public List<int> coordinates = new List<int>();
}
And the problem is: how to loop through this CSparseMatrix and output all ranges with values in format like: [0, 0, 0, 0] - *value*, [0, 0, 0, 1] - *value*, [0, 0, 0, 2] - *value*, ...[dimensionsRanges[0]-1, dimensionsRanges[1]-1, dimensionsRanges[2]-1, dimensionsRanges[3]-1] - *value* so through all ranges and output all values (we can have any number of this dimensions).
That means that in program we had to to output all values of matrix, which can have any number of dimensions and ranges could be different. But we don't know what this number of dimensions will be so can't use n-nested loops, and actually I have no idea of algorithm or method how to iterate through all values from List<int> dimensionsRanges
The way, we get the specific value from this "matrix" is
public int GetValueFromCell(List<int> coordinate)
{
foreach(CSparseCell cell in cells)
{
if(cell.coordinates.All(coordinate.Contains)) {
return cell.Value;
}
}
return DefaultNumber;
}
Since you say your matrix is large, avoid returning CSparseCell by pushing the Value lookup to the answer computation.
You create a method to return all the coordinates in the sparse matrix, using a helper method to increment coordinates. NOTE: I changed the coordinate increment method to use a for loop instead of do which might be easier to understand (?).
void IncCoord(ref List<int> aCoord) { // ref not needed, just for documentation
for (var curDim = NumberOfDimensions - 1; curDim >= 0; --curDim) {
if (aCoord[curDim] == dimensionsRanges[curDim] - 1) // handle carry
aCoord[curDim] = 0;
else {
++aCoord[curDim];
break;
}
}
}
public IEnumerable<List<int>> AllCoords() {
var curCellCoord = Enumerable.Repeat(0, NumberOfDimensions).ToList();
var numCells = dimensionsRanges.Product();
for (int j1 = 0; j1 < numCells; ++j1) {
yield return curCellCoord.ToList();
IncCoord(ref curCellCoord);
}
}
Now you can use this method to get all Values and you can format the output however you like. Assuming t is a CSparseMatrix:
var ans = t.AllCoords().Select(c => $"[{c.Join(",")}] - {t.GetValueFromCell(c)}");
A couple of helper extension methods are used:
public static class IEnumerableExt {
public static int Product(this IEnumerable<int> src) => src.Aggregate(1, (a,n) => a * n);
}
public static class StringExt {
public static string Join<T>(this IEnumerable<T> items, string sep) => String.Join(sep, items);
}
I'd make a couple suggestions. First tying the coordinate and the value together complicate things. It'd be much better to separate those two.
Secondly, having to search the entire array to find a single cell makes it very inefficient. You can create a simple sparse matrix out of a dictionary. This not at all the best way but with the unknown key requirements you have given it's at least better than the array. (is it really a matrix if the key is 1..n ?)
Here's an example. First we make the coordinates their own type.
readonly struct SparseCoord : IEquatable<SparseCoord>
{
public static SparseCoord ToCoordinate(params int[] coords)
{
return new SparseCoord(coords);
}
public SparseCoord(int[] c)
{
this.Coordinate = new int[c?.Length ?? 0];
if (null != c)
c.CopyTo(this.Coordinate, 0);
}
public int[] Coordinate { get; }
public bool Equals([AllowNull] SparseCoord other)
{
return Enumerable.SequenceEqual(this.Coordinate, other.Coordinate);
}
public override bool Equals(object obj)
{
if (obj is SparseCoord c)
return this.Equals(c);
return false;
}
public override int GetHashCode()
{
var hash = new HashCode();
foreach (var i in this.Coordinate)
hash.Add(i);
return hash.ToHashCode();
}
public override string ToString()
{
StringBuilder sb = new StringBuilder();
sb.Append('(');
foreach (var i in this.Coordinate)
{
sb.Append(i);
sb.Append(',');
}
sb.Length = sb.Length - 1;
sb.Append(')');
return sb.ToString();
}
}
Then we create a sparse matrix using a dictionary as the storage. Note this is incomplete obviously as there's no way to clear it partially or completely but again it's just an example.
class SparseMatrix : IEnumerable<KeyValuePair<SparseCoord, int>>
{
Dictionary<SparseCoord, int> cells = new Dictionary<SparseCoord, int>();
public int this[SparseCoord coord]
{
get
{
if (this.cells.TryGetValue(coord, out var ret))
return ret;
return 0;
}
set
{
this.cells[coord] = value;
}
}
public IEnumerator<KeyValuePair<SparseCoord, int>> GetEnumerator()
{
return this.cells.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return this.GetEnumerator();
}
}
Then you can add values and iterate over the contents:
static void Main(string[] _)
{
SparseMatrix matrix = new SparseMatrix();
matrix[SparseCoord.ToCoordinate(1, 2, 3)] = 1;
matrix[SparseCoord.ToCoordinate(5, 6, 7)] = 2;
foreach (var value in matrix)
Console.WriteLine(value);
}
Finally I would reiterate that if your matrix really is going to get "big" as you said in a comment then you should invest some time in looking at some well known implementations of sparse matrix.

How do I approach array properties when I need an array to have an interval in C#?

I am extremely new to C# and am still trying to wrap my head around some of its core concepts.First time posting a question to StackOverflow.
So this is what I need help with:
Make a property for: private string array; : so that:
"Each element of an array needs to be >=0 and <=10"
Should I run it through for, and then set array=value for each element or what?
This is what I did:
private string array;
public int[] Array
{
get { return array; } //-is this part good for the task?
set
{
//what do I do here to make sure the elements are withing the
//given interval?
}
}
See if this is what you need (Demo):
public class myClass
{
private int[] _Array = new int[10];
public int this[int index]
{
get { return _Array[index]; }
set
{
if (value >= 0 && value <= 10)
_Array[index] = value;
}
}
}
public class Program
{
public static void Main(string[] args)
{
myClass m = new myClass();
m[0] = 1;
m[1] = 12;
Console.WriteLine(m[0]); // outputs 1
Console.WriteLine(m[1]); // outputs default value 0
}
}
You are looking for something like this
private int[] _privateArray;
public int[] PublicArray
{
get
{
return _privateArray;
}
set
{
foreach (int val in value)
{
if (val < 0 || val > 10) throw new ArgumentOutOfRangeException();
}
// if you get to here you can set value
_privateArray = (int[])value.Clone();
}
}
please note private property and public property must be same type

Using Indexers for multiple Arrays in the class c#

I have two arrays in my Base class, and I want to create Indexers that can be used in both of them, attached below is an MVCE of what I am trying to do.
class Indexer
{
private string[] namelist = new string[size];
private char[] grades = new string[size];
static public int size = 10;
public IndexedNames() {
for (int i = 0; i < size; i++){
namelist[i] = "N. A.";
grades[i] = 'F';
}
}
public string this[int index] {
get {
string tmp;
if( index >= 0 && index <= size-1 ) {
tmp = namelist[index];
} else {
tmp = "";
}
return ( tmp );
}
set {
if( index >= 0 && index <= size-1 ) {
namelist[index] = value;
}
}
}
In the above coed if you comment out the lines private char[] grades = new string[size]; and grades[i] = 'F'; then you can use the indexers as object_name[i] but I want to be able to access both namelist and grades by indexers.
Note : I cannot use structures to wrap them together as in my application, there size may not always be same.
Is this possible or I would need to go around with some hack.
Edit
I am looking for something like names.namelist[i] and names.grades[i], or some statements that I can access them separately. Also Indexer logic is not consistent, and even size varies in some arrays, that was skipped here to aid simplicity in MVCE.
Sorry, no-can-do.
Although Indexers can be Overloaded and can have more than one formal parameter, you can't make two variations based on the same Parameter in the same class. This is a Language Limitation (or blessing).
Indexers (C# Programming Guide)
However, this should lead you to several options.
You can just make use of C#7. Ref returns
Starting with C# 7.0, C# supports reference return values (ref
returns). A reference return value allows a method to return a
reference to a variable, rather than a value, back to a caller. The
caller can then choose to treat the returned variable as if it were
returned by value or by reference. The caller can create a new
variable that is itself a reference to the returned value, called a
ref local.
public ref string Namelist(int position)
{
if (array == null)
throw new ArgumentNullException(nameof(array));
if (position < 0 || position >= array.Length)
throw new ArgumentOutOfRangeException(nameof(position));
return ref array[position];
}
...
// Which allows you to do funky things like this, etc.
object.NameList(1) = "bob";
You could make sub/nested classes with indexers
That's to say, you could create a class that has the features you need with indexers, and make them properties of the main class. So you get something like you envisaged object.Namelist[0] and object.Grades[0].
Note : in this situation you could pass the arrays down as references and still access them in the main array like you do.
Example which includes both:
Given
public class GenericIndexer<T>
{
private T[] _array;
public GenericIndexer(T[] array)
{
_array = array;
}
public T this[int i]
{
get => _array[i];
set => _array[i] = value;
}
}
Class
public class Bobo
{
private int[] _ints = { 2, 3, 4, 5, 5 };
private string[] _strings = { "asd","asdd","sdf" };
public Bobo()
{
Strings = new GenericIndexer<string>(_strings);
Ints = new GenericIndexer<int>(_ints);
}
public GenericIndexer<string> Strings ;
public GenericIndexer<int> Ints ;
public void Test()
{
_ints[0] = 234;
}
public ref int DoInts(int pos) => ref _ints[pos];
public ref string DoStrings(int pos) => ref _strings[pos];
}
Usage:
var bobo = new Bobo();
bobo.Ints[1] = 234;
bobo.DoInts(1) = 42;
I think only a two parameter indexer can achieve what you want.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
namespace ConsoleApp1
{
class MyClass
{
protected static Dictionary<string, FieldInfo[]> table = new Dictionary<string, FieldInfo[]>();
static public int size = 10;
protected char[] grades = new char[size];
public object this[string name, int index]
{
get
{
var fieldInfos = table[this.GetType().FullName];
return ((Array)fieldInfos.First((x) => x.Name == name).GetValue(this)).GetValue(index);
}
set
{
var fieldInfos = table[this.GetType().FullName];
((Array)fieldInfos.First((x) => x.Name == name).GetValue(this)).SetValue(value, index);
}
}
static void Main()
{
var names = new MyChildClass();
names[DataColumns.Grades, 1] = 'S';
names[DataColumns.NameList, 9] = "W.S";
}
}
class MyChildClass : MyClass
{
private string[] namelist = new string[size];
static MyChildClass()
{
var t = typeof(MyChildClass);
table.Add(t.FullName, t.GetFields(BindingFlags.NonPublic | BindingFlags.Instance));
}
public MyChildClass()
{
for (int i = 0; i < size; i++)
{
namelist[i] = "N. A.";
grades[i] = 'F';
}
}
}
static class DataColumns
{
public static string NameList = "namelist";
public static string Grades = "grades";
}
}
Maybe something like this:
class Indexer
{
private string[] namelist = new string[size];
private string[] grades = new string[size + 1]; // size +1 to indicate different
// size
static public int size = 10;
public void IndexedNames()
{
for (int i = 0; i < size; i++)
{
namelist[i] = "N. A.";
grades[i] = "F";
}
}
public string this[int i, int j]
{
get
{
string tmp;
// we need to return first array
if (i > 0)
{
tmp = namelist[i];
}
else
{
tmp = grades[i];
}
return (tmp);
}
set
{
if (i > 0)
{
namelist[i] = value;
}
else grades[i] = value;
}
}
}

C# array accessiblity

Is there a way to prevent reinitialization of an array? (to force specific length)
example initial:
int[] array = new int[3]{0,0,0};
usage:
array = new int[5]{1,2,3,4,5};
The above usage will reinitialize the array with length of 5.
The array will always have 3 elements, but the values of the elements will always be changing.
I am trying to avoid doing the following to assign it's values:
array[0] = 1;
array[1] = 2;
array[2] = 3;
Try declaring it readonly:
readonly int[] array = new int[3]{0,0,0};
I am not sure whether it is what you want, but I can propose to you the following wrapper class:
public class FixedArrayHolder<T>
{
public FixedArrayHolder(Int32 fixedLength, T[] array)
{
if (fixedLength < 0)
throw new ArgumentOutOfRangeException();
if (array == null)
throw new ArgumentNullException();
this.FixedLength = fixedLength;
this.Array = array;
}
public Int32 FixedLength
{
get;
private set;
}
private T[] m_array;
public T[] Array
{
get
{
return this.m_array;
}
set
{
if (value == null)
throw new ArgumentNullException();
if (value.Length != this.FixedLength)
throw new ArgumentException();
this.m_array = value;
}
}
public static implicit operator T[](FixedArrayHolder<T> fixedArray)
{
if (fixedArray == null)
return null;
return fixedArray.Array;
}
}
You can use this class in place of standard arrays:
// Works
var array = new FixedArrayHolder<Int32>(3, new Int32[] { 1, 2, 3 });
// Works
array.Array = new Int32[] { 3, 4, 5 };
// Fails
array.Array = new Int32[] { 1, 2, 3, 4 };
P.S.: You can extend it with some indexer and IEnumerable, IList members to allow more streamlined access to elements if it is required.
private int[] origin = new int[3];
public int[] Origin {
get { return origin;}
set{
if (value.Length >3) throw new ArgumentOutOfRangeException();
else origin = value;
}
}
Don't expose the field. Make it as property. Validate the value in property setter. – Sriram Sakthivel
This worked perfectly, thanks!
I think you should encapsulate the array in a class, instantiating it from the constructor. Use a public getter and private setter to control access:
public int[] MyArray {
get;
private set;
}
Fiddle: https://dotnetfiddle.net/ZsjrsN

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