Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Creating arrays dynamically in Perl

Tags:

arrays

perl

I want to create arrays dynamically based on the user input. For example, if the user gives input as 3 then three arrays should be created with the name @message1, @message2, and @message3.

How do I do it in Perl?

like image 451
Senthil kumar Avatar asked Aug 23 '10 06:08

Senthil kumar


4 Answers

Don't. Instead, use an array of arrays:

my @message;
my $input = 3;
for my $index ( 0..$input-1 ) {
    $message[$index][0] = "element 0";
    $message[$index][1] = 42;
}
print "The second array has ", scalar( @{ $message[1] } ), " elements\n";
print "They are:\n";
for my $index ( 0..$#{ $message[1] } ) {
    print "\t", $message[1][$index], "\n";
}

Some helpful rules are at http://perlmonks.org/?node=References+quick+reference

like image 110
ysth Avatar answered Sep 27 '22 21:09

ysth


I have to ask why you want to do this, because it's not the right way to go. If you have three streams of input, each of which needs to be stored as a list, then store one list, which is a list of the lists (where the lists are stored as array references):

my @input = (
    [ 'data', 'from', 'first', 'user' ],
    [ qw(data from second user) ],
    [ qw(etc etc etc) ],
);

If you have names associated with each user's data, you might want to use that as a hash key, for indexing the data against:

my %input = (
    senthil => [ 'data', 'from', 'first', 'user' ],
    ether => [ qw(data from second user) ],
    apu => [ qw(etc etc etc) ],
);

Please refer to the Perl Data Structures Cookbook (perldoc perldsc) for more on selecting the right data structure for the situation, and how to define them.

like image 43
Ether Avatar answered Sep 27 '22 21:09

Ether


Creating new named arrays dynamically is almost never a good idea. Mark Dominus, author of the enlightening book Higher-Order Perl, has written a three-part series detailing the pitfalls.

You have names in mind for these arrays, so put them in a hash:

sub create_arrays {
  my($where,$n) = @_;

  for (1 .. $n) {
    $where->{"message$_"} = [];
  }
}

For a quick example that shows the structure, the code below

my $n = @ARGV ? shift : 3;

my %hash;
create_arrays \%hash, $n;

use Data::Dumper;
$Data::Dumper::Indent = $Data::Dumper::Terse = 1;
print Dumper \%hash;

outputs

$ ./prog.pl
{
  'message2' => [],
  'message3' => [],
  'message1' => []
}

Specifying a different number of arrays, we get

$ ./prog.pl 7
{
  'message2' => [],
  'message6' => [],
  'message5' => [],
  'message4' => [],
  'message3' => [],
  'message1' => [],
  'message7' => []
}

The order of the keys looks funny because they're inside a hash, an unordered data structure.

Recall that [] creates a reference to a new anonymous array, so, for example, to add values to message2, you'd write

push @{ $hash{"message2"} }, "Hello!";

To print it, you'd write

print $hash{"message2"}[0], "\n";

Maybe instead you want to know how long all the arrays are:

foreach my $i (1 .. $n) {
  print "message$i: ", scalar @{ $hash{"message$i"} }, "\n";
}

For more details on how to use references in Perl, see the following documentation:

  • Mark's very short tutorial about references, or perldoc perlreftut
  • Perl references and nested data structures, or perldoc perlref
  • Perl Data Structures Cookbook, or perldoc perldsc
like image 21
Greg Bacon Avatar answered Sep 27 '22 19:09

Greg Bacon


In compiled languages, variables don't have a name. The name you see in the code is a unique identifier associated with some numerical offset. In an identifier like message_2 the '2' only serves to make it a unique identifier. Anybody can tell that you could make your three variables: message_125, message_216, and message_343. As long as you can tell what you should put into what, they work just as well as message_1...

The "name" of the variable is only for you keeping them straight while you're writing the code.

Dynamic languages add capability by not purging the symbol table(s). But a symbol table is simply an association of a name with a value. Because Perl offers you lists and hashes so cheaply, there is no need to use the programming/logistical method of keeping track of variables to allow a flexible runtime access.

Chances are that if you see yourself naming lists @message1, @message2, ... -- where the items differ only by their reference order, that these names are just as good: $message[1], $message[2], ....

In addition, since symbol tables are usually mapping from name-to-offset (either on the stack or in the heap), it's really not a whole lot more than a key-value pair you find in a hash. So hashes work just as good for looking up more distinct names.

$h{messages} = [];
$h{replies}  = [];

I mean really if you wanted to, you could store everything that you put into a lexical variable into a single hash for the scope, if you didn't mind writing: $h{variable_name} for everything. But you wouldn't get the benefit of Perl's implicit scope management, and across languages, programmers have preferred implicit scope management.

Perl allows symbolic manipulation, but over the years the dynamic languages have found that a mixed blessing. But in Perl you have both "perspectives", to give them a name. Because you can determine what code in a compiled language is likely to do better than a dynamic language, it has been determined more error free to use a "compiled perspective" for more things: So as you can see with the availability of offset-management and lookup compiled behavior given to you in core Perl, there is no reason to mess with the symbol table, if you don't have to.

Creating an array dynamically, is as simple as: []. Assigning it to a spot in memory, when we don't know how many we want to store, is as easy as:

push @message, [];

And creating a list of lists all at once is as easy as:

@message = map { [] } 1..$num_lists;

for some specified value in $num_lists.

like image 37
Axeman Avatar answered Sep 27 '22 19:09

Axeman