Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations Chriss Miller on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

Calling arrays from arrays 3

Status
Not open for further replies.

audiopro

Programmer
Joined
Apr 1, 2004
Messages
3,165
Location
GB
I am automating the reading from three arrays and need to access the array names from within an array. It is purely a syntax issue but I am pulling my hair out.
The arrays are named something like this, although I may be declaring the names incorrectly.
Code:
@ARRAY_NAMES=("PRO_FILE","CON_FILE","BID_FILE");
I need to programatically read the contents of any one of 3 multidimensional arrays which are declared before this point in the script. The script is written and functions as expected but I need to condense the code into a single sub routine in order to make for manageable house keeping.
Manual access syntax is:-
Code:
$FILE_ITEM=$PRO_FILE[4][8];
$FILE_ITEM=$CON_FILE[6][2];
$FILE_ITEM=$BID_FILE[8][4];
Any help would be greatly appreciated.

Keith
 
Keith

Can you put the arrays into a hash?
Code:
use strict;
use warnings;

my (@a1, @a2, @a3);

$a1[1][1] = "PRO #1";
$a2[2][2] = "CON #2";
$a3[3][3] = "BID #3";

my %arrays = ('PROS' => \@a1,
              'CONS' => \@a2,
              'BIDS' => \@a3);
              
print $arrays{"CONS"}->[2][2];
then you can have 'named' access to arrays declared elsewhere. Alternatively, if you don't like thae hashes, just change the % to @ and get rid of the hash keys, after which you can address items as
Code:
use strict;
use warnings;

my (@a1, @a2, @a3);

$a1[1][1] = "PRO #1";
$a2[2][2] = "CON #2";
$a3[3][3] = "BID #3";

my @arrays = (\@a1,
              \@a2,
              \@a3);
              
print $arrays[1]->[2][2];

Steve
 
I'd agree that Steve's suggestion is the way to go. What you're trying to do can be acheived with symbolic (soft) references, but that's considered a bad idea.
 
Sorry guys but it is Monday and the brain / eyes are not too good.
Code:
change the % to @ and get rid of the hash keys
I do not understand what is going on in your examples.
Why is a multi dim array declared for the three single array names or am I just being numb?

Keith
 
Referencing the arrays by name is dangerous, scales badly and can cause huge debugging headaches if it all goes `pear-shaped'.

Steve is suggesting that, instead of holding the arrays' names somewhere, you can store references to those arrays instead. He's presented hash and array-based solutions - which you choose is down to whether you want to be able to reference them by name (hash) or not (array).
 
[ol][li]You said you had three multidimensional arrays, already declared and populated in your program. These equate to my @a1 - @a3. I populated them with one entry each to show how it works.[/li][li]In the hash example, references to these arrays are loaded into the hash with keys CONS, PROS, and BIDS. In the array example $arrays[0] holds a reference to @a1, $arrays[1] a reference to @a2, and so on.[/li][li]The print statement in both examples shows how to reference a specific item. If you cut & paste the examples, you can see what prints out.[/li][/ol]Or there is always the possibility that I've completly misunderstood what you were trying to achieve...
 
Thanks for the explanation Steve.
Now it makes sense, I was confusing your creating an example array with part of the solution.
Have a * for your trouble.
Could you explain the literal meaning of your line of code:-
Code:
$arrays[1]->[2][2];
I read it as a named part of the object on the left but not too sure if it has a more logical meaning.
I have found a reference to it in my reference book but the explanation is very brief and meaningless.

Keith
 
The @arrays array contains references to the three other arrays, so $arrays[1] is a reference to @a2.

Therefore, this is exactly the same as:
Code:
$a2[2][2];

 
So it has to be written that way as $a2[1][2][2] would create a syntax error. That is precisely what my original problem was although I am glad I asked you guys before wasting time on a poor procedure.
Why is referencing arrays by name dangerous?
Please don't think I am questioning your advice, I simply like to know the reason as I may be doing similar things which could give me problems.

Keith
 
The quick version:
[link]http://www.perl.com/doc/FMTEYEWTK/style/slide24.html[/url]

The long version (this is an article that I references quite frequently):
[link]http://perl.plover.com/varvarname.html[/url]

The basic thrust of both is that they cause more problems than they solve, and they're easily avoided by using hashes.
 
Keith

You can think of an array reference as a pointer to an array. It's not a copy of the array, it points to the real thing. In order to de-reference the pointer, you need the -> syntax. As a mnemonic, you can think of $arrays{BIDS}->[5][6] as entry [5][6] in the array pointed to by hash entry $arrays{BIDS}. Likewise, as ishnid has noted, $arrays[1]->[2][2]; can be read as 'entry [2][2] in the array pointed to by $arrays[1]'

When you are using structures like this, Data::Dumper is an invaluable tool
Code:
user Data::Dumper;
..
..
..
print Dumper(@array);
will print out the contents of the whole structure from the top down, with indentation so you can see exactly what's going on.
 
You guys blow me away, I'm unsure why you would have an array of arrays, but am curious, as I can't understand the syntax correctly, does....
Code:
$arrays[1]->[2][2];

equates to....

you want the first element of $arrays with $arrays[1], which contains an array so you are asking for the second element of that array with ->[2], but why then the second [2].

sorry if its a stupid question, but if you don't ask!

 
This particular case is an `array of arrays of arrays'!

$arrays[1] returns the second element (not the first, since that's index 0) of @arrays. In this case, it's a reference to another array.

$arrays[1][2] (the `->' isn't strictly necessary) gets the third element of the array we got the reference to with $arrays[1]. This, in this situation, is also a reference to an array.

$arrays[1][2][2] gets the third element of *that* array, which is presumably something usable (we haven't seen audiopro's data so I'm assuming).

Try googling for `perllol' if you need to read up more on multidimensional arrays (of if I've confused the hell out of you).
 
As for why you'd need a multidimensional array:- well, that's entirely up to the kind of data you're trying to represent.

Here's a contrived example. Supposing I'm holding the current position of a number of chess games in one data structure.

The logical data structure for this board position would be a an `array of arrays' - one dimension for the ranks (rows) and one for files (columns). If I'm storing a few boards, I need an array of chessboards (or an ``array of `arrays of arrays'''.

Example code:
Code:
my @boards = (
   [
      [ 'r', 'n', 'b', 'k', 'q', 'b', 'n', 'r' ],
      [ 'p', 'p', 'p', 'p', 'p', 'p', 'p', 'p' ],
      [ ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ' ],
      [ ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ' ],
      [ ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ' ],
      [ ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ' ],
      [ 'P', 'P', 'P', 'P', 'P', 'P', 'P', 'P' ],
      [ 'R', 'N', 'B', 'K', 'Q', 'B', 'N', 'R' ]
   ],
   [
      [ 'r', 'n', 'b', 'k', 'q', 'b', 'n', 'r' ],
      [ 'p', 'p', ' ', ' ', 'p', 'p', 'p', 'p' ],
      [ ' ', ' ', 'p', ' ', ' ', ' ', ' ', ' ' ],
      [ ' ', ' ', ' ', 'p', ' ', ' ', ' ', ' ' ],
      [ ' ', ' ', ' ', 'P', ' ', ' ', ' ', ' ' ],
      [ ' ', ' ', ' ', ' ', ' ', 'N', ' ', ' ' ],
      [ 'P', 'P', 'P', ' ', 'P', 'P', 'P', 'P' ],
      [ 'R', 'N', 'B', 'K', 'Q', 'B', ' ', 'R' ]
   ],
);

print '[', $boards[1][2][2], "]\n";

So:
$boards[1] - the second board
$boards[1][2] - the third rank in the second board
$boards[1][2][2] - the third file of the third rank on the second board (which currently has a pawn in it).
 
ahh thanks ishnid, sorry about the clumsy mistake [1] of course thats element 2 i knew that, d'oh!

now it makes sense that it is an array of arrays holding arrays, wow, complicated or what, Is there some sort of benefit doing it this way, I understand the use of matricies, but it's use an array of hashes to achieve that.

but an array of arrays of arrays, to hold a chess board i'd use an array of hashes...

$Board[1]{'A'} = "Rook";

i'd skip element [0] so the logic looked like the actual board co-ordinates that are used 'A1' etc...

so Row 1 Column A holds piece "Rook".

is it just down to preference at the end of the day ?
 
What data structure to use can often be a matter of preference, as in this case.

Personally, I'd stick with the arrays for a chess board, as I think they'd be easier to work with calculations on numbers internally rather than using letter-based hash keys.

For example, a subroutine to check for a legal move for a bishop (ignoring for the moment the case of another piece being in the way) could be as simple as:
Code:
# move from A4 (0,3) to B3 (1,2) - legal move
print "ok\n" if( legal_bishop( 0, 3, 1, 2 ) );

# move from A4 (0,3) to B4 (1,3) - illegal move - not diagonal
print "ok\n" if( legal_bishop( 0, 3, 1, 3 ) );

# move from A4 (0,3) to B9 (1,8) - illegal move - outside the board
print "ok\n" if( legal_bishop( 0, 3, 1, 8 ) );


sub legal_bishop {
   my ( $from_file, $from_rank, $to_file, $to_rank ) = @_;

   # check if the co-ordinates are off the board
   return 0 if ( grep +( $_ < 0 || $_ > 7 ), $from_rank, $from_file, $to_rank, $to_file );

   # check the path is diagonal
   return 0 if ( abs( $from_rank - $to_rank ) != abs( $from_file - $to_file ) );

   # return true if nothing's wrong
   return 1;
}

It's a matter of opinion really.
 
Your a smart guy isnid, I see how it might be easier mathematically , but not reader friendly.

also whats the grep? , that's a unix command isn't it, are you scanning a file holding the acceptable moves for each piece in seperate files for each co-ordinate.

would this work on a windows box with ActiveState perl?
 
There is a Unix command called `grep' but that's not to be confused with Perl's grep function (which will work fine on Windows too).

The format for grep (the way I've used it) is:
grep EXPR, LIST

LIST is simply a list of values - in my example above, the list is $from_rank, $from_file, $to_rank, $to_file.

EXPR is some code that's executed on each item in the list. Each line is, in turn, stored in $_ and EXPR is run. In my example, EXPR will return true if the value being tested is less than 0 or greater than 7 (i.e. outside the constraints of the board) and false otherwise.

grep will return a list of all the elements of LIST for which EXPR evaluated to true (i.e. all that are outside the board).

With me so far?

Using an `if' statement on a list returns true if there are any elements in that list, and false if the list is empty. In this case, it'll be true if there's anything in LIST that's outside the board, and false if they're all inside the board. The entire line very roughly translates logically as ``return false if any of the points specified are outside the chessboard''.

If you want to read more, type ``perldoc -f grep'' on your command line.
 
but not reader friendly.

admittedly it's confusing at first glance, but really it's not hard to read at all once you understand the logic of multi-dimensional data structures.
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top