www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Two-dimensional associateive arrays?

reply Tyler <Tyler_member pathlink.com> writes:
I'm working on converting a program from C to D and one of the data structures
in it could be more easily represented in D as an associative array of arrays of
2 integers (i.e. "int[char[]][2] example;")  Can D do this?  The latgest DMD
compiler lets me declare it, but when I try to use it ("example["foo"][1] =
55;") it gives me errors about how it can't implicitly cast char[] to int.
Feb 02 2006
next sibling parent reply Chris Sauls <ibisbasenji gmail.com> writes:
Tyler wrote:
 I'm working on converting a program from C to D and one of the data structures
 in it could be more easily represented in D as an associative array of arrays
of
 2 integers (i.e. "int[char[]][2] example;")  Can D do this?  The latgest DMD
 compiler lets me declare it, but when I try to use it ("example["foo"][1] =
 55;") it gives me errors about how it can't implicitly cast char[] to int.
 
 

Its a simple, and common mistake for thsoe new to D arrays. The basic thing to remember, is that decleration and usage are in reverse syntactic directions, and declerations are "read" from right to left. In other words: # // declare # int[2][char[]] example; # # // use # example["foo"c][1] = 55; In the case above, the decleration "reads" as "an association of char[]'s to static arrays, length 2, of int's." Your original decleration "reads" as "a static array, length 2, of associations of char[]'s to int's." -- Chris Sauls
Feb 02 2006
parent reply Ivan Senji <ivan.senji_REMOVE_ _THIS__gmail.com> writes:
Chris Sauls wrote:
 Tyler wrote:
 
 I'm working on converting a program from C to D and one of the data 
 structures
 in it could be more easily represented in D as an associative array of 
 arrays of
 2 integers (i.e. "int[char[]][2] example;")  Can D do this?  The 
 latgest DMD
 compiler lets me declare it, but when I try to use it 
 ("example["foo"][1] =
 55;") it gives me errors about how it can't implicitly cast char[] to 
 int.

Its a simple, and common mistake for thsoe new to D arrays. The basic thing to remember, is that decleration and usage are in reverse syntactic directions, and declerations are "read" from right to left. In other words: # // declare # int[2][char[]] example; # # // use # example["foo"c][1] = 55;

Common mistake indeed, but the above doesn't work. Instead you get ArrayBoundsError. Why would that be?
Feb 02 2006
next sibling parent reply Chris Sauls <ibisbasenji gmail.com> writes:
Ivan Senji wrote:
 Chris Sauls wrote:
 
 Tyler wrote:

 I'm working on converting a program from C to D and one of the data 
 structures
 in it could be more easily represented in D as an associative array 
 of arrays of
 2 integers (i.e. "int[char[]][2] example;")  Can D do this?  The 
 latgest DMD
 compiler lets me declare it, but when I try to use it 
 ("example["foo"][1] =
 55;") it gives me errors about how it can't implicitly cast char[] to 
 int.

Its a simple, and common mistake for thsoe new to D arrays. The basic thing to remember, is that decleration and usage are in reverse syntactic directions, and declerations are "read" from right to left. In other words: # // declare # int[2][char[]] example; # # // use # example["foo"c][1] = 55;

Common mistake indeed, but the above doesn't work. Instead you get ArrayBoundsError. Why would that be?

I had to think about it for a bit, but I know why... and it dregs up an ancient topic. It issues the ArrayBoundsError because the key "foo" does not yet exist. Now, normally an assignment expression creates the key, but apparently when one includes extra dimensions then D doesn't catch this. Bug? Or annoying feature? -- Chris Sauls
Feb 02 2006
parent reply Ivan Senji <ivan.senji_REMOVE_ _THIS__gmail.com> writes:
Chris Sauls wrote:
 I had to think about it for a bit, but I know why... and it dregs up an 
 ancient topic.  It issues the ArrayBoundsError because the key "foo" 
 does not yet exist.  Now, normally an assignment expression creates the 
 key, but apparently when one includes extra dimensions then D doesn't 
 catch this.
 
 Bug?  Or annoying feature?

As you said assignment normally creates the key, so i would vote for bug. But the bigger problem is how would one manully create a static array. It just isn't possible. If examples was int[][char[]] example, you could do something like example["foo"] = makeArray!(int)(55,56); but in this case is there anything that can be done?
 
 -- Chris Sauls

Feb 02 2006
next sibling parent reply Chris Sauls <ibisbasenji gmail.com> writes:
Ivan Senji wrote:
 Chris Sauls wrote:
 
 I had to think about it for a bit, but I know why... and it dregs up 
 an ancient topic.  It issues the ArrayBoundsError because the key 
 "foo" does not yet exist.  Now, normally an assignment expression 
 creates the key, but apparently when one includes extra dimensions 
 then D doesn't catch this.

 Bug?  Or annoying feature?

As you said assignment normally creates the key, so i would vote for bug. But the bigger problem is how would one manully create a static array. It just isn't possible. If examples was int[][char[]] example, you could do something like example["foo"] = makeArray!(int)(55,56); but in this case is there anything that can be done?
 -- Chris Sauls


# template makeStaticArray!(T_Type, size_t T_Size) { # T_Type[T_Size] makeStaticArray(T_Type[] data ...) { # if (data.length == T_Size) # return cast(T_Type[T_Size]) data; # throw new Exception(format("makeStaticArray: received %d items, expected %d"), data.length, T_Size)); # } # } Maybe? -- Chris Sauls
Feb 02 2006
parent Ivan Senji <ivan.senji_REMOVE_ _THIS__gmail.com> writes:
Chris Sauls wrote:
 Ivan Senji wrote:
 As you said assignment normally creates the key, so i would vote for bug.

 But the bigger problem is how would one manully create a static array. 
 It just isn't possible.

 If examples was int[][char[]] example, you could do something like
 example["foo"] = makeArray!(int)(55,56); but in this case is there 
 anything that can be done?

 -- Chris Sauls


# template makeStaticArray!(T_Type, size_t T_Size) { # T_Type[T_Size] makeStaticArray(T_Type[] data ...) { # if (data.length == T_Size) # return cast(T_Type[T_Size]) data; # throw new Exception(format("makeStaticArray: received %d items, expected %d"), data.length, T_Size)); # } # }

Nice template..
 Maybe?

But with the folowing problems: - functions can not return static arrays - you can not assign to static array
Feb 02 2006
prev sibling parent reply Bruno Medeiros <daiphoenixNO SPAMlycos.com> writes:
Ivan Senji wrote:
 Chris Sauls wrote:
 I had to think about it for a bit, but I know why... and it dregs up 
 an ancient topic.  It issues the ArrayBoundsError because the key 
 "foo" does not yet exist.  Now, normally an assignment expression 
 creates the key, but apparently when one includes extra dimensions 
 then D doesn't catch this.

 Bug?  Or annoying feature?

As you said assignment normally creates the key, so i would vote for bug.

example["foo"] = ... and not: example["foo"][2] = ... Because the latter is index assignment of the static array, not of the associative array.
 But the bigger problem is how would one manully create a static array. 
 It just isn't possible.
 

is that you cannot assign to static arrays, so this will never work: example["foo"] = ... -> What could probably be made, is to not allow creation of types of the following structure: int[2][] example; That is, one can't create dynamic arrays with static elements. -- Bruno Medeiros - CS/E student "Certain aspects of D are a pathway to many abilities some consider to be... unnatural."
Feb 09 2006
parent reply Ivan Senji <ivan.senji_REMOVE_ _THIS__gmail.com> writes:
Bruno Medeiros wrote:
 Ivan Senji wrote:
 As you said assignment normally creates the key, so i would vote for bug.

example["foo"] = ... and not: example["foo"][2] = ... Because the latter is index assignment of the static array, not of the associative array.

I realized that. So there is now solution to the problem of associative array of static arrays.
 
 But the bigger problem is how would one manully create a static array. 
 It just isn't possible.

is that you cannot assign to static arrays, so this will never work: example["foo"] = ...

That is exactly what my "just isn't possible" meant.
 
 
 
 -> What could probably be made, is to not allow creation of types of the
 following structure:
    int[2][] example;
 

NOOO! Are you trying to break my existing code? :) This works and i use this! There is no reason why this wouldn't work.
 That is, one can't create dynamic arrays with static elements.

Yes, one can, but can't create associative arrays of static arrays.
Feb 09 2006
parent Bruno Medeiros <daiphoenixNO SPAMlycos.com> writes:
Ivan Senji wrote:
 Bruno Medeiros wrote:
 Ivan Senji wrote:

 But the bigger problem is how would one manully create a static 
 array. It just isn't possible.

is that you cannot assign to static arrays, so this will never work: example["foo"] = ...

That is exactly what my "just isn't possible" meant.

isn't possible to create a static arrays [literal]. (They're different things)
 -> What could probably be made, is to not allow creation of types of the
 following structure:
    int[2][] example;

NOOO! Are you trying to break my existing code? :) This works and i use this! There is no reason why this wouldn't work.
 That is, one can't create dynamic arrays with static elements.

Yes, one can, but can't create associative arrays of static arrays.

Damn, you are correct. It is true my initial assumption that you also can not do this (assign to a static array) with dynamic arrays: example[10] = ... ; //(assign to a static array) So I was thinking that dynamic arrays with static elements wouldn't work too. However, I forgot that in the case of dynamic arrays, one can create elements by changing length. Thus the following is possible: example.length = 10 example[0][] = ... ; //(copy to a static array, that is ok) -- Bruno Medeiros - CS/E student "Certain aspects of D are a pathway to many abilities some consider to be... unnatural."
Feb 10 2006
prev sibling parent reply Russ Lewis <spamhole-2001-07-16 deming-os.org> writes:
Ivan Senji wrote:
 Chris Sauls wrote:
 
 Tyler wrote:

 I'm working on converting a program from C to D and one of the data 
 structures
 in it could be more easily represented in D as an associative array 
 of arrays of
 2 integers (i.e. "int[char[]][2] example;")  Can D do this?  The 
 latgest DMD
 compiler lets me declare it, but when I try to use it 
 ("example["foo"][1] =
 55;") it gives me errors about how it can't implicitly cast char[] to 
 int.

Its a simple, and common mistake for thsoe new to D arrays. The basic thing to remember, is that decleration and usage are in reverse syntactic directions, and declerations are "read" from right to left. In other words: # // declare # int[2][char[]] example; # # // use # example["foo"c][1] = 55;

Common mistake indeed, but the above doesn't work. Instead you get ArrayBoundsError. Why would that be?

The integer array (i.e. the init value of example["foo"]) inits to length 0. Try this: int[2][char[]] example; example["foo"].length = 2; example["foo"][1] = 55;
Feb 06 2006
parent reply Ivan Senji <ivan.senji_REMOVE_ _THIS__gmail.com> writes:
Russ Lewis wrote:
 The integer array (i.e. the init value of example["foo"]) inits to 
 length 0.  Try this:
 
 
 
 int[2][char[]] example;
 example["foo"].length = 2;

You can't set length of a static array, you get (as expected): constant example["foo"].length is not an lvalue Am I the only one that is (again) begining to think that although D does some thing with arrays great for example slicing and ~, that there are very very big flaws? What I thing D is missing are two types of dynamic arrays: 1. The one we have now: int[][] bla = new int[2]; bla[0].length = 5; bla[1].length = 100; 2. Dynamic rectangular arrays: int[,] bla = new int[7,3]; //for example in C# Static arrays can be useful sometimes but many many times i don't know the exact size at compile-time but still want a tightly packed multidimensional rectangular array.
 example["foo"][1] = 55;

Feb 07 2006
next sibling parent Russ Lewis <spamhole-2001-07-16 deming-os.org> writes:
Ivan Senji wrote:
 Russ Lewis wrote:
 
 The integer array (i.e. the init value of example["foo"]) inits to 
 length 0.  Try this:



 int[2][char[]] example;
 example["foo"].length = 2;

You can't set length of a static array, you get (as expected):

Sorry, can't believe I overlooked that.
Feb 07 2006
prev sibling parent reply Derek Parnell <derek psych.ward> writes:
On Tue, 07 Feb 2006 14:56:11 +0100, Ivan Senji wrote:


[snip]
 
 2. Dynamic rectangular arrays:
 
 int[,] bla = new int[7,3]; //for example in C#
 
 Static arrays can be useful sometimes but many many times i don't know 
 the exact size at compile-time but still want a tightly packed 
 multidimensional rectangular array.

In the meantime, you can do this sort of thing ... template InitRectArray(T) { T[][] InitRectArray(int i, int j) { T[][] lTemp; lTemp.length = i; lTemp[] = new T[j]; return lTemp; } } import std.stdio; void main() { int[][] bla; bla = InitRectArray!(int)(7,3); foreach( int i, int[] a; bla ) { foreach(int j, int b; a) { writefln(i, "," , j); } } } -- Derek (skype: derek.j.parnell) Melbourne, Australia "Down with mediocracy!" 8/02/2006 11:50:53 AM
Feb 07 2006
parent Ivan Senji <ivan.senji_REMOVE_ _THIS__gmail.com> writes:
Derek Parnell wrote:
 On Tue, 07 Feb 2006 14:56:11 +0100, Ivan Senji wrote:
 
 
 [snip]
  
 
2. Dynamic rectangular arrays:

int[,] bla = new int[7,3]; //for example in C#

Static arrays can be useful sometimes but many many times i don't know 
the exact size at compile-time but still want a tightly packed 
multidimensional rectangular array.

In the meantime, you can do this sort of thing ...

Thanks for the answer. Yes i do these sort of things but that is not the point. The point is: arrays are the most basic concept of a language. Far more basic than even classes and delegates, and doing it right in the language is important. It is funny how you can do all these wonderfull thing with arrays like dynamically resize and slice them, have associative arrays... but also not to be able to use array literals or dynamic rectangular arrays.
 
 template InitRectArray(T)
 {
     T[][] InitRectArray(int i, int j)
     {
         T[][] lTemp;
         lTemp.length = i;
         lTemp[] = new T[j];
 
         return lTemp;
     }
 }
 
 import std.stdio;
 void main()
 {
 
     int[][] bla;
 
     bla = InitRectArray!(int)(7,3);
     foreach( int i, int[] a; bla )
     {
         foreach(int j, int b; a)
         {
             writefln(i, "," , j);
         }
     }
 }
 

Although this template does allow to emulate the creation of a rectangular-looking array it in fact isn't. Rectangular array must be continuous in memory, not a bunch of references to 1D arrays.
Feb 07 2006
prev sibling next sibling parent reply "Regan Heath" <regan netwin.co.nz> writes:
On Thu, 2 Feb 2006 20:23:00 +0000 (UTC), Tyler <Tyler_member pathlink.com>  
wrote:
 I'm working on converting a program from C to D and one of the data  
 structures
 in it could be more easily represented in D as an associative array of  
 arrays of
 2 integers (i.e. "int[char[]][2] example;")  Can D do this?  The latgest  
 DMD
 compiler lets me declare it, but when I try to use it  
 ("example["foo"][1] =
 55;") it gives me errors about how it can't implicitly cast char[] to  
 int.

I believe that sort of array should be declared: int[2][char[]] example; Further "55;" is a string literal, in this case a char[], not a fixed array of 2 integers. However, part of the problem you are going to have is the inability to define a fixed array of 2 integers without making it "static". void foo(int[2] a) {} void main() { int[2] a = [1,2]; //fails static int[2] b = [1,2]; //works foo(b); //works foo([2,3]); //fails } Further, you can't create a dynamic array of integers either, eg. void bar(int[] a) {} void main() { bar([2,3]); //fails } I believe the intention is to support this at a later stage. However, right now there are a number of templates which can achieve this. I don't have one but someone else is likely to post one for you. So, I suspect the way you're going to have to solve this is.. int[][char[]] example; example["label"] = makeArray!(int)(1,2); or similar, where makeArray is the template I mentioned. Alternately if your values come in string form a function like.. int[] parseIntPair(char[] data) { } which converts from the string into a dynamic array of integers could be used. Regan
Feb 02 2006
parent reply BCS <BCS_member pathlink.com> writes:
Regan Heath wrote:
 On Thu, 2 Feb 2006 20:23:00 +0000 (UTC), Tyler 
 <Tyler_member pathlink.com>  wrote:

with a little reformatting...
 [...] ("example["foo"][1] = 55;") [...]


quoted code, not quotes in code.
 
 Further "55;" is a string literal, in this case a char[], not a fixed  
 

Feb 02 2006
parent "Regan Heath" <regan netwin.co.nz> writes:
On Thu, 02 Feb 2006 12:52:32 -0800, BCS <BCS_member pathlink.com> wrote:
 Regan Heath wrote:
 On Thu, 2 Feb 2006 20:23:00 +0000 (UTC), Tyler  
 <Tyler_member pathlink.com>  wrote:

with a little reformatting... >> [...] ("example["foo"][1] = 55;") [...] quoted code, not quotes in code.
  Further "55;" is a string literal, in this case a char[], not a fixed


Oops, my apologies. Regan
Feb 02 2006
prev sibling parent reply Tyler <Tyler_member pathlink.com> writes:
Thanks for all your help!  I decided that it would just be easier to use a
struct like I did in the C version.  Now I have another question though.  I have
a structure (not related to the first question) containing a 2 dynamic arrays of
ints, like this:

struct EXAMPLE_STRUCT {
int[] fooLenghts;
int[] barLenghts;
}

When I try to use either fooLenghts or barLenghts (see below for an example) DMD
tells me that there is no property 'fooLenghts' for type 'EXAMPLE_STRUCT'.  What
am I doing wrong?

void someFunc(inout EXAMPLE_STRUCT example)
{
example.fooLengths.length = length + 1; //DMD: no property 'fooLenghts' for type
'EXAMPLE_STRUCT'
example.fooLenghts[length-1] = 55; //(same message)
}
Feb 02 2006
parent reply "Regan Heath" <regan netwin.co.nz> writes:
On Fri, 3 Feb 2006 04:37:04 +0000 (UTC), Tyler <Tyler_member pathlink.com>  
wrote:
 Thanks for all your help!  I decided that it would just be easier to use  
 a
 struct like I did in the C version.  Now I have another question  
 though.  I have
 a structure (not related to the first question) containing a 2 dynamic  
 arrays of
 ints, like this:

 struct EXAMPLE_STRUCT {
 int[] fooLenghts;
 int[] barLenghts;
 }

 When I try to use either fooLenghts or barLenghts (see below for an  
 example) DMD
 tells me that there is no property 'fooLenghts' for type  
 'EXAMPLE_STRUCT'.  What
 am I doing wrong?

 void someFunc(inout EXAMPLE_STRUCT example)
 {
 example.fooLengths.length = length + 1; //DMD: no property 'fooLenghts'  
 for type
 'EXAMPLE_STRUCT'
 example.fooLenghts[length-1] = 55; //(same message)
 }

Typo "fooLengths" != "fooLenghts" the h and t are switched. Regan
Feb 02 2006
parent reply Tyler <Tyler_member pathlink.com> writes:
D'oh!  Thanks for pointing out that typo.  After staring at that code for a good
while I have no clue how I missed it (and now it works!)
Feb 03 2006
parent reply Tyler <Tyler_member pathlink.com> writes:
Alright, now I have another question.  I finally got the program to compile, but
when I run it I get an array out of bounds error while trying to do the
following:

struct INNER_STRUCT {
int foo;
int bar;
}

struct EAMPLE_STRUCT {
OTHER_STRUCT[] unimportant; //(should be) unrelated to problem
INNER_STRUCT[char[]] inner;
}

//global variable
EXAMPLE_STRUCT example;

/* ...SNIP... */

example.inner[exampString].foo = 15; //Generates ArrayBoundsError (exampString
is a char[] of non-zero length)
Feb 03 2006
next sibling parent James Dunne <james.jdunne gmail.com> writes:
Tyler wrote:
 Alright, now I have another question.  I finally got the program to compile,
but
 when I run it I get an array out of bounds error while trying to do the
 following:
 
 struct INNER_STRUCT {
 int foo;
 int bar;
 }
 
 struct EAMPLE_STRUCT {
 OTHER_STRUCT[] unimportant; //(should be) unrelated to problem
 INNER_STRUCT[char[]] inner;
 }
 
 //global variable
 EXAMPLE_STRUCT example;
 
 /* ...SNIP... */
 
 example.inner[exampString].foo = 15; //Generates ArrayBoundsError (exampString
 is a char[] of non-zero length)
 
 

I'd have to see more code...
Feb 03 2006
prev sibling parent reply "Unknown W. Brackets" <unknown simplemachines.org> writes:
Looks to me like example.inner is a dynamic array.  You'll probably have 
to do:

INNER_STRUCT temp_inner;
temp_inner.foo = 15;
example.inner[exampString] = temp_inner;

D used to create keys on read and write, but now it does so only on 
write.  In your example, you're reading from the associative array, and 
then writing to the result of that.

For an example using code, consider this struct:

struct X
{
	int y;
}

This code fails with an ArrayBoundsError:

int main()
{
	X[char[]] x;
	x["test"].y= 1;

	return 0;
}

This code works:

int main()
{
	X[char[]] x;
	X temp_x;

	temp_x.y = 1;
	x["test"] = temp_x;

	return 0;
}

You could also do this:

int main()
{
	X[char[]] x;
	X temp_x;

	x["test"] = temp_x;
	x["test"].y = 1;

	return 0;
}

Or use a more complicated template.

Hope that helps,
-[Unknown]


 Alright, now I have another question.  I finally got the program to compile,
but
 when I run it I get an array out of bounds error while trying to do the
 following:
 
 struct INNER_STRUCT {
 int foo;
 int bar;
 }
 
 struct EAMPLE_STRUCT {
 OTHER_STRUCT[] unimportant; //(should be) unrelated to problem
 INNER_STRUCT[char[]] inner;
 }
 
 //global variable
 EXAMPLE_STRUCT example;
 
 /* ...SNIP... */
 
 example.inner[exampString].foo = 15; //Generates ArrayBoundsError (exampString
 is a char[] of non-zero length)
 
 

Feb 04 2006
parent reply Deewiant <deewiant.doesnotlike.spam gmail.com> writes:
Unknown W. Brackets wrote:
 This code works:
 
 int main()
 {
     X[char[]] x;
     X temp_x;
 
     temp_x.y = 1;
     x["test"] = temp_x;
 
     return 0;
 }
 
 You could also do this:
 
 int main()
 {
     X[char[]] x;
     X temp_x;
 
     x["test"] = temp_x;
     x["test"].y = 1;
 
     return 0;
 }
 
 Or use a more complicated template.
 

This also works, but I'm not so sure it's supposed to: struct X { int y; } void main() { X[char[]] x; x["test"] = *new X; x["test"].y = 1; } Is it allowed to use new like that?
Feb 04 2006
parent reply "Jarrett Billingsley" <kb3ctd2 yahoo.com> writes:
"Deewiant" <deewiant.doesnotlike.spam gmail.com> wrote in message 
news:ds2q7t$2cgg$1 digitaldaemon.com...
 This also works, but I'm not so sure it's supposed to:

 struct X { int y; }

 void main() {
 X[char[]] x;
 x["test"] = *new X;
 x["test"].y = 1;
 }

 Is it allowed to use new like that?

Yeah, all you're doing is copying the values of the new X (i.e. the default values for an X) into the slot. You can also skip the new and just use x["test"] = X.init; That works as well.
Feb 04 2006
parent reply "Unknown W. Brackets" <unknown simplemachines.org> writes:
Ah, that looks nicer.  I should have done/thought of that.

-[Unknown]


 "Deewiant" <deewiant.doesnotlike.spam gmail.com> wrote in message 
 news:ds2q7t$2cgg$1 digitaldaemon.com...
 This also works, but I'm not so sure it's supposed to:

 struct X { int y; }

 void main() {
 X[char[]] x;
 x["test"] = *new X;
 x["test"].y = 1;
 }

 Is it allowed to use new like that?

Yeah, all you're doing is copying the values of the new X (i.e. the default values for an X) into the slot. You can also skip the new and just use x["test"] = X.init; That works as well.

Feb 04 2006
parent Tyler <Tyler_member pathlink.com> writes:
Thanks again everyone.
Feb 05 2006