471,317 Members | 1,519 Online
Bytes | Software Development & Data Engineering Community
Post +

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 471,317 software developers and data experts.

Referencing [,] element as [ ]?

I have a two-dimensional array with 6 x 7 elements. I'd like to be able to
reference the elements sequentially, as if the rows were laid end-to-end. I
know the Array.Length property will give me the length of the array as 42,
but I'd like to be able to reference specific elements. For example, I'd
like to be able to reference foo[3,2] as foo[24].

Is there any way to do this natively in C#? Right now I'm using a conversion
function that takes an index and returns a cell reference. I'd like to
eliminate the function, if I can. Thanks in advance.

--
David Veeneman
Foresight Systems
Jan 19 '06 #1
14 1412
Something like this?

foo[Math.Floor(24/7),24%7] // foo[24]

In C you could fo what you say, but they were just downright nasty memory
overruns that happened to work...

"David Veeneman" <da****@nospam.com> wrote in message
news:%2***************@TK2MSFTNGP12.phx.gbl...
I have a two-dimensional array with 6 x 7 elements. I'd like to be able to
reference the elements sequentially, as if the rows were laid end-to-end. I
know the Array.Length property will give me the length of the array as 42,
but I'd like to be able to reference specific elements. For example, I'd
like to be able to reference foo[3,2] as foo[24].

Is there any way to do this natively in C#? Right now I'm using a
conversion function that takes an index and returns a cell reference. I'd
like to eliminate the function, if I can. Thanks in advance.

--
David Veeneman
Foresight Systems

Jan 19 '06 #2
David Veeneman wrote:
I have a two-dimensional array with 6 x 7 elements. I'd like to be able to
reference the elements sequentially, as if the rows were laid end-to-end. I
know the Array.Length property will give me the length of the array as 42,
but I'd like to be able to reference specific elements. For example, I'd
like to be able to reference foo[3,2] as foo[24].

Is there any way to do this natively in C#? Right now I'm using a conversion
function that takes an index and returns a cell reference. I'd like to
eliminate the function, if I can. Thanks in advance.


I don't think so. Your best strategy may be to allocate your array as
a 43 element array. That way, the code that needs to deal with rows
and columns can call your product and sum methods, while the code that
can deal with vectors goes straight to the vector.

--
<http://www.midnightbeach.com>
Jan 19 '06 #3
David Veeneman wrote:
I have a two-dimensional array with 6 x 7 elements. I'd like to be able to
reference the elements sequentially, as if the rows were laid end-to-end. I
know the Array.Length property will give me the length of the array as 42,
but I'd like to be able to reference specific elements. For example, I'd
like to be able to reference foo[3,2] as foo[24].

Is there any way to do this natively in C#? Right now I'm using a conversion
function that takes an index and returns a cell reference. I'd like to
eliminate the function, if I can. Thanks in advance.


Just in case anyone else was investigating this line of enquiry - using
the IList indexer implementation for arrays doesn't work. For instance:

using System;
using System.Collections;

class Test
{
static void Main()
{
string[,] array = new string[10,20];
array[0,5] = "Hello";
array[3,4] = "There";

IList list = (IList)array;

Console.WriteLine (list[5]);
Console.WriteLine (list[64]);
}
}

compiles but gives the following result:
Unhandled Exception: System.ArgumentException: Array was not a
one-dimensional array.
at System.Array.GetValue(Int32 index)
at System.Array.System.Collections.IList.get_Item(Int 32 index)
at Test.Main()

(Using 2.0 and generics doesn't help either as far as I can see.)

Jon

Jan 19 '06 #4
On Wed, 18 Jan 2006 19:28:32 -0600, "David Veeneman"
<da****@nospam.com> wrote:
I have a two-dimensional array with 6 x 7 elements. I'd like to be able to
reference the elements sequentially, as if the rows were laid end-to-end.


That's not directly possible with .NET arrays, at least not in C#.
However, you could access the array with foreach -- the iterator will
loop through all elements sequentially, but you won't know the current
overall index unless you keep track of it yourself.
--
http://www.kynosarges.de
Jan 19 '06 #5
Christoph Nahr wrote:
I have a two-dimensional array with 6 x 7 elements. I'd like to be able to
reference the elements sequentially, as if the rows were laid end-to-end.
That's not directly possible with .NET arrays, at least not in C#.
However, you could access the array with foreach -- the iterator will
loop through all elements sequentially, but you won't know the current
overall index unless you keep track of it yourself.


In fact, it's not just C#. As far as I can tell, IL doesn't have any
direct instructions for accessing an array element unless the array is
actually a vector (in CLI terminology) - a single-dimensional array
with a lower bound of 0.
From the CLI spec (first edition, admittedly), section 4.7 of partition

III:

<quote>
The ldelem instruction loads the value of the element with index
'index' (of type int32 or native int) in the zero-based, one
dimensional array 'array' and places it on the top of the stack.
....
For one-dimesional arrays that aren't zero-based, and for
multi-dimensional arrays, the array class provides a Get method.
</quote>

Of course, it wouldn't be hard to write an ArrayUtil class which took
an arbitrary Array and an index, then use GetUpperBounds etc to access
the relevant element. It wouldn't be very efficient though...

Jon

Jan 19 '06 #6
I was afraid that was the case. For the benefit of anyone else researching
the question, here is the code I use to get a cell reference from an index
number. It assumes a 6 x 7 array:
private CellRef GetCellRefFromIndex(int index)
{
// Get the row number for the index passed in
int row = index / 7;

// Get the column number for the index passed in
int column = (index % 7) - 1;
if (column == -1) column = 6;

// Set return value
return new CellRef(row, column);
}
The code returns a CellRef, which is a custom struct:
private struct CellRef
{
public int Row;
public int Column;

public CellRef(int row, int column)
{
Row = row;
Column = column;
}
}


Jan 19 '06 #7
David Veeneman wrote:
// Get the column number for the index passed in
int column = (index % 7) - 1;
if (column == -1) column = 6;


Looks like 1 <= index <= 43. Fwiw,

int column = (index - 1) % 7;

should be more efficient than your code, with its conditional
statement.

--
<http://www.midnightbeach.com>
Jan 19 '06 #8
On Wed, 18 Jan 2006 19:28:32 -0600, "David Veeneman"
<da****@nospam.com> wrote:
I have a two-dimensional array with 6 x 7 elements. I'd like to be able to
reference the elements sequentially, as if the rows were laid end-to-end. I
know the Array.Length property will give me the length of the array as 42,
but I'd like to be able to reference specific elements. For example, I'd
like to be able to reference foo[3,2] as foo[24].

Is there any way to do this natively in C#? Right now I'm using a conversion
function that takes an index and returns a cell reference. I'd like to
eliminate the function, if I can. Thanks in advance.


You could wrap the underlying array in a class and provide two
separate indexers: [] and [,]. For reasons of speed I have used one
dimension rather than two for the underlying array. YMMV.

public class CellRefArray {
private int m_rows;
private int m_cols;
private CellRef[] m_CRArray;

// Constructor
public CellRefArray(int rows, int cols) {
m_rows = rows;
m_cols = cols;
m_CRArray = new CellRef[m_rows * m_cols];
}

// Indexer[]
public CellRef this[int i] {
get { return m_CRArray[i]; }
set { m_CRArray[i] = value; }
}

// Indexer[,]
public CellRef this[int r, int c] {
get { return m_CRArray[r * m_cols + c]; }
set { m_CRArray[r * m_cols + c] = value; }
}
}

You may want to add some range checking to the two indexers.

Depending on precisely what you want you might also want to add a
second constructor that takes an array[,] as parameter or a property
that returns an array[,].

rossum
--

The ultimate truth is that there is no ultimate truth
Jan 19 '06 #9
Jon Shemitz <jo*@midnightbeach.com> wrote:
David Veeneman wrote:
// Get the column number for the index passed in
int column = (index % 7) - 1;
if (column == -1) column = 6;


Looks like 1 <= index <= 43. Fwiw,

int column = (index - 1) % 7;

should be more efficient than your code, with its conditional
statement.


However, it's not equivalent. The index 0 would give column=-1 with
your code, but column=6 for David's. To make it equivalent, however
(for non-negative values of "index") you could use (index+6)%7 instead.

Alternatively, it would be worth trying Math.DivRem. I haven't
benchmarked it, so I've no idea whether it would be faster or not - but
if efficiency is critical, it's worth a try.

I'm not sure why David's subtracting one in the first place, however...
I don't think he should be doing so.

--
Jon Skeet - <sk***@pobox.com>
http://www.pobox.com/~skeet Blog: http://www.msmvps.com/jon.skeet
If replying to the group, please do not mail me too
Jan 19 '06 #10
Jon Skeet [C# MVP] <sk***@pobox.com> wrote:
Jon Shemitz <jo*@midnightbeach.com> wrote:
David Veeneman wrote:
// Get the column number for the index passed in
int column = (index % 7) - 1;
if (column == -1) column = 6;


Looks like 1 <= index <= 43. Fwiw,

int column = (index - 1) % 7;

should be more efficient than your code, with its conditional
statement.


However, it's not equivalent. The index 0 would give column=-1 with
your code, but column=6 for David's. To make it equivalent, however
(for non-negative values of "index") you could use (index+6)%7 instead.


Doh, sorry, missed the first line of your reply. Assuming a positive
value for index, your code is equivalent. Maybe I should just go to bed
now...

However, I still think there's a bug in David's code. Here's the
index/row/column values:

1/0/0
2/0/1
3/0/2
4/0/3
5/0/4
6/0/5
7/1/6 <-- Bug!
8/1/0
9/1/1
10/1/2
11/1/3
12/1/4
13/1/5
14/2/6 <-- Bug!

(etc)

Basically, if the index is to be treated as 1-based, it should be
treated that way consistently for both the row and the column.

(Personally I'd suggest just using a zero-based index to start with,
but there we go.)

--
Jon Skeet - <sk***@pobox.com>
http://www.pobox.com/~skeet Blog: http://www.msmvps.com/jon.skeet
If replying to the group, please do not mail me too
Jan 19 '06 #11
"Jon Skeet [C# MVP]" wrote:
Looks like 1 <= index <= 43. Fwiw,

int column = (index - 1) % 7;

should be more efficient than your code, with its conditional
statement.
However, it's not equivalent. The index 0 would give column=-1 with
your code, but column=6 for David's.


Yes, this is why I assume he's using a 1-based index.
To make it equivalent, however
(for non-negative values of "index") you could use (index+6)%7 instead.


True.

--
<http://www.midnightbeach.com>
Jan 19 '06 #12
Why not just create your own collection class and implement the indexers
to do what you want?


rossum wrote:
On Wed, 18 Jan 2006 19:28:32 -0600, "David Veeneman"
<da****@nospam.com> wrote:
I have a two-dimensional array with 6 x 7 elements. I'd like to be able to
reference the elements sequentially, as if the rows were laid end-to-end. I
know the Array.Length property will give me the length of the array as 42,
but I'd like to be able to reference specific elements. For example, I'd
like to be able to reference foo[3,2] as foo[24].

Is there any way to do this natively in C#? Right now I'm using a conversion
function that takes an index and returns a cell reference. I'd like to
eliminate the function, if I can. Thanks in advance.


You could wrap the underlying array in a class and provide two
separate indexers: [] and [,]. For reasons of speed I have used one
dimension rather than two for the underlying array. YMMV.

public class CellRefArray {
private int m_rows;
private int m_cols;
private CellRef[] m_CRArray;

// Constructor
public CellRefArray(int rows, int cols) {
m_rows = rows;
m_cols = cols;
m_CRArray = new CellRef[m_rows * m_cols];
}

// Indexer[]
public CellRef this[int i] {
get { return m_CRArray[i]; }
set { m_CRArray[i] = value; }
}

// Indexer[,]
public CellRef this[int r, int c] {
get { return m_CRArray[r * m_cols + c]; }
set { m_CRArray[r * m_cols + c] = value; }
}
}

You may want to add some range checking to the two indexers.

Depending on precisely what you want you might also want to add a
second constructor that takes an array[,] as parameter or a property
that returns an array[,].

rossum
--

The ultimate truth is that there is no ultimate truth

Jan 19 '06 #13
John Murray <jm*****@pluck.com> wrote:
Why not just create your own collection class and implement the indexers
to do what you want?


Isn't that exactly what rossum did?

--
Jon Skeet - <sk***@pobox.com>
http://www.pobox.com/~skeet Blog: http://www.msmvps.com/jon.skeet
If replying to the group, please do not mail me too
Jan 19 '06 #14
Missed that one -- *grin*
Jon Skeet [C# MVP] wrote:
John Murray <jm*****@pluck.com> wrote:
Why not just create your own collection class and implement the indexers
to do what you want?


Isn't that exactly what rossum did?

Jan 20 '06 #15

This discussion thread is closed

Replies have been disabled for this discussion.

Similar topics

4 posts views Thread by Bosconian | last post: by
1 post views Thread by JavaDeveloper | last post: by
5 posts views Thread by Tim Johnson | last post: by
6 posts views Thread by Mikey_Doc | last post: by
reply views Thread by Doug Gault | last post: by
10 posts views Thread by rshepard | last post: by
2 posts views Thread by Mystagogue | last post: by
reply views Thread by rosydwin | last post: by

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.