Dynamic array creation in perl [duplicate] - arrays

This question already has answers here:
How can I use a variable as a variable name in Perl?
(3 answers)
Closed 7 years ago.
I have read this post and saw that there are various ways to create a dynamic naming of arrays in perl.
http://en.allexperts.com/q/Perl-CGI-1045/dynamic-naming-array-1.htm
as per the link, the code will create dynamic arrays like these:
#yearsSoFar2004,
#yearsSoFar2005,
#yearsSoFar2006 etc.
My requirement is as follows. I want to create a dynamic array like this:
my #a0=();
my #a1=();
my #a2=();
my #a3=();
I currently have it static in my code but i want to make it dynamic. Here is the static code below. Please help me guys. I am a newbie to PERL
my #a=();
my #b=();
my #c=();
my #d=();

Three problems with your request:
my declares a lexical variable at compile-time, so asking to pass a name to my at run-time makes no sense.
Symbolic references can't be used to access lexical variables.
It's a stupid thing to do.

My requirement is as follows. I want to create a dynamic array like this:
my #a0=();
my #a1=();
my #a2=();
my #a3=();
As I have said before, "When you find yourself adding an integer suffix to variable names, think I should have used an array."
So, instead, use
my #data = (
[ ... ],
[ ... ],
[ ... ],
);
If you wanted index each year's data array by the year (instead of integers 0, 1, 2, ..., n), then use a hash:
my %data = (
2005 => [ ... ],
2006 => [ ... ],
2007 => [ ... ],
);
What you have now is compounded stupidity. Don't do that.

Related

is it possible to reference an index position in a nested array? Ruby

im to Ruby; I see theres been various questions on this topic..but cant find one like this bu I gather multidimensional arrays don't exist in ruby as such. So im working with a nested array for a fictitious data set. is it possible to reference an index position for a child element in a nested array? I've figured iterating through and creating a block for each array is the best way forward (and confirmed this on SO). i see in another article its recommended to use the Narray library...does this work with strings? my first aim is to print out each name and the last area of interest. ive put an example of what im roughly trying to achieve in the example.. many thanks
staff_array = [
["paulBarry",
["programming", "networking", "security", "open source" ,"frameworks"]],
["chrisMuedec",
["testing", "safety systems", "formal systems", "programming languages"]],
["nigelwhite",
["graphics", "imaging", "programming","sign languages","trees"]],
["austinKinsella",
["networks", "wans", "programming", "macintosh", "digital photography"]],
["gerryMoloney",
["placement", "employment", "emerging systems", "webdevelopment"]
]
]
staff.each do |name_array|
# Iterate through the parent array, returning each element sequentially
name_array.each do |interest_element|
# Iterate through each element of the child array returned by the above parent iteration
Example:
puts {#name_array}+ name_array.each do |interest_element|[-1]
end
end
Expected output would be:
Paulbarry: Frameworks
ChrisMuedec: Programming languages
Nigelwhite: Trees
AustinKinsella: Digital photography
GerryMoloney: Webdevelopment.
Ruby has nested arrays. You reference index positions with the [] method starting at 0, no matter the nesting level.
array = [
[
['0.0.0', '0.0.1', '0.0.2'],
['0.1.0', '0.1.1', '0.1.2'],
['0.2.0', '0.2.1', '0.2.2'],
],
[
['1.0.0', '1.0.1', '1.0.2'],
['1.1.0', '1.1.1', '1.1.2'],
['1.2.0', '1.2.1', '1.2.2'],
],
[
['2.0.0', '2.0.1', '2.0.2'],
['2.1.0', '2.1.1', '2.1.2'],
['2.2.0', '2.2.1', '2.2.2'],
],
]
array[0][0][0] # => '0.0.0'
array[0][1][2] # => '0.1.2'
array[2][2][2] # => '2.2.2'
There are also some specific methods like first and last.
array.first.first.first # => '0.0.0'
array.last.last.last # => '2.2.2'
my first aim is to print out each name and the last area of interest.
staff_array.each do |name, interests|
puts "#{name.sub(/./) { |m| m.upcase }}: #{interests.last.capitalize}"
end
Output:
PaulBarry: Frameworks
ChrisMuedec: Programming languages
Nigelwhite: Trees
AustinKinsella: Digital photography
GerryMoloney: Webdevelopment
Perhaps from this first step you can infer how to generalize to answering your other questions.

How to have an instance variable that is an array

I would like to create a smalltalk application with a class that has an instance variable that is an array and an instance variable that is the array's size. I would ideally like to initialise these when the object gets created but I have these manually being initialised in a method.
The following is my code:
Object subclass: Student [
| numTests marks |
initialize [
numTests := 0.
marks := Array new: 10.
]
]
student := Student new.
student initialize.
But I get the following error:
Object: Array new: 10 "<0x10b054b80>" error: method is responsibility of a subclass
How can I solve this problem?
You may not really want to do this. I generally use Squeak derivatives and Array new: works but is often not what you want because Arrays are fixed size (i.e. you can't add or remove elements) and so you typically use something like OrderedCollection instead. Also, you generally don't want to store the size in an ivar but rather send #size to your collection whenever you need to know how many elements it contains.
I've modified your code example based on the above suggestions (also notice that you don't need to send #initialize explicitly, it's done for you via #new:):
Object subclass: Student [
| marks |
initialize [
marks := OrderedCollection new: 10.
].
addMark: newMark [
marks add: newMark
].
removeMarkAt: markIdx [
marks removeAt: markIdx
].
size [
^ marks size
]
]
student := Student new.
If you really need to create a fixed size array, please update the question with which Smalltalk variant you are using so that someone with specific knowledge of the implementation can help. The problem you appear to be running into is that your Smalltalk implementation considers Array an abstract class and therefore you need to instantiate a subclass of it to get a fixed size array.

In Perl 6, can I use an Array as a Hash key?

In the Hash documentation, the section on Object keys seems to imply that you can use any type as a Hash key as long as you indicate but I am having trouble when trying to use an array as the key:
> my %h{Array};
{}
> %h{[1,2]} = [3,4];
Type check failed in binding to parameter 'key'; expected Array but got Int (1)
in block <unit> at <unknown file> line 1
Is it possible to do this?
The [1,2] inside the %h{[1,2]} = [3,4] is interpreted as a slice. So it tries to assign %h{1} and %{2}. And since the key must be an Array, that does not typecheck well. Which is what the error message is telling you.
If you itemize the array, it "does" work:
my %h{Array};
%h{ $[1,2] } = [3,4];
say %h.perl; # (my Any %{Array} = ([1, 2]) => $[3, 4])
However, that probably does not get what you want, because:
say %h{ $[1,2] }; # (Any)
That's because object hashes use the value of the .WHICH method as the key in the underlying array.
say [1,2].WHICH; say [1,2].WHICH;
# Array|140324137953800
# Array|140324137962312
Note that the .WHICH values for those seemingly identical arrays are different.
That's because Arrays are mutable. As Lists can be, so that's not really going to work.
So what are you trying to achieve? If the order of the values in the array is not important, you can probably use Sets as keys:
say [1,2].Set.WHICH; say [1,2].Set.WHICH
# Set|AEA2F4CA275C3FE01D5709F416F895F283302FA2
# Set|AEA2F4CA275C3FE01D5709F416F895F283302FA2
Note that these two .WHICHes are the same. So you could maybe write this as:
my %h{Set};
dd %h{ (1,2).Set } = (3,4); # $(3, 4)
dd %h; # (my Any %{Set} = ((2,1).Set) => $(3, 4))
Hope this clarifies things. More info at: https://docs.raku.org/routine/WHICH
If you are really only interested in use of an Object Hash for some reason, refer to Liz's answer here and especially the answers to, and comments on, a similar earlier question.
The (final1) focus of this answer is a simple way to use an Array like [1,'abc',[3/4,Mu,["more",5e6],9.9],"It's {<sunny rainy>.pick} today"] as a regular string hash key.
The basic principle is use of .perl to approximate an immutable "value type" array until such time as there is a canonical immutable Positional type with a more robust value type .WHICH.
A simple way to use an array as a hash key
my %hash;
%hash{ [1,2,3].perl } = 'foo';
say %hash{ [1,2,3].perl }; # displays 'foo'
.perl converts its argument to a string of Perl 6 code that's a literal version of that argument.
say [1,2,3].perl; # displays '[1, 2, 3]'
Note how spaces have been added but that doesn't matter.
This isn't a perfect solution. You'll obviously get broken results if you mutate the array between key accesses. Less obviously you'll get broken results corresponding to any limitations or bugs in .perl:
say [my %foo{Array},42].perl; # displays '[(my Any %{Array}), 42]'
1 This is, hopefully, the end of my final final answer to your question. See my earlier 10th (!!) version of this answer for discussion of the alternative of using prefix ~ to achieve a more limited but similar effect and/or to try make some sense of my exchange with Liz in the comments below.

Perl: Parentheses vs Brackets for array definition, why is one considered a scalar?

I was following this tutorial on the HTML::Template module for Perl. Here's the template:
<!--template2.tmpl-->
<html>
<body>
<table>
<tr>
<th>Language</th>
<th>Description</th>
</tr>
<tmpl_loop name="language">
<tr>
<td><tmpl_var name="language_name"></td>
<td><tmpl_var name="description"></td>
</tr>
</tmpl_loop>
</table>
</body>
</html>
And here's the CGI test program:
#!"C:\Strawberry\perl\bin\perl.exe" -wT
use CGI qw(:all);
use CGI::Carp qw(fatalsToBrowser);
use HTML::Template;
my #rows = (
{
language_name => 'C#',
description => 'Created by Microsoft'
},
{
language_name => 'PHP',
description => 'Hypertext Preprocessor'
},
{
language_name => 'Haskell',
description => 'Functional language'
},
);
print header;
my $template=HTML::Template->new(filename=>'template2.tmpl');
$template->param(language => #rows);
print $template->output();
This fails with the following error: HTML::Template::param() : attempt to set parameter 'language' with a scalar - parameter is not a TMPL_VAR!
However, when I change the definition of #rows from using parenthesis to using square brackets(from my #rows=(...) to my #rows = [...]) the code works fine; it displays a table with the data.
As I understood from reading this article, the first form is an array defined from a list and the second one is a reference to an anonymous array. It's still not clear to me why the first form doesn't work. I'd appreciate you clarifying this for me.
The tutorial you're following contains an error. The line
$template->param( language => #languages );
should be
$template->param( language => \#languages );
Why? Short answer: the right-hand side of the loop name you pass to param must be a reference to an array, not an array.
Long answer: When you pass arguments to a function or method, all of the arguments get expanded into one long list. This is a common source of mistakes for beginners. So in your code (and in the tutorial's code), you're not passing two parameters to the param method, you're passing four (one for the string 'language', and three for the elements of #languages.
Here's an example of this argument-list unraveling. If you have three variables as follows:
my $scalar = 'bear';
my #array = ('rat', 'moose', 'owl');
my %hash = (mass => 500, units => 'kg');
and you pass them to a function like so:
some_function($scalar, #array, %hash);
then the function will see eight arguments: 'bear', 'rat', 'moose', 'owl', 'mass', 500, 'units', and 'kg'! Perhaps even more surprising, the two sets of values from the hash might be passed in a different order, because hashes are not stored or retrieved in a determinate order.
Your solution of changing the parentheses to square brackets works, but not for a very good reason. Parentheses delimit lists (which can be stored in arrays or hashes); square brackets delimit references to arrays. So your square-bracket code creates a reference to an anonymous array, which is then stored as the first (and only) element of your named array #rows. Instead, you should either store the array reference (delimited with square brackets) in a scalar variable (say, $rows), or you should use parentheses, store the list in the array #rows, and pass a reference to that array to the param method (by using a backslash, as I did above with \#languages).
language => #rows
means
'language', $rows[0], $rows[1], $rows[2], ...
or
language => $rows[0],
$rows[1] => $rows[2],
...
You want
language => \#rows
The param() method in HTML::Template takes pairs of arguments. The first value in the pair is the name of a template variable that you want to set and the second is the value that you want to set that variable to.
So you can make a call that sets a single variable:
$template->param(foo => 1);
Or you can set multiple variables in one call:
$template->param(foo => 1, bar => 2, baz => 3);
For reasons that should be obvious, the variable names given in your call to param() should all be variables that are defined in your template (either as standard tmpl_var variables or as looping tmpl_loop variables).
If you're setting a tmpl_loop variable (as you are in this case) then the associated value needs to be a reference to an array containing your values. There is some attempt to explain this in the documentation for param(), but I can see how it might be unclear as it just does it by showing examples in square (array reference constructor) brackets rather than actually explaining the requirement.
The reason for this is that the list of parameters passed to a subroutine in Perl is "flattened" - so an array is broken up into its individual elements. This means that when you pass:
$template->param(languages => #rows);
Perl sees it as:
$template->param(languages => $row[0], $row[1] => $row[2]);
The elements of your array are hash references. This means that $row[1] will be interpreted as a stringified hash reference (something like "HASH(0x12345678)") which definitely isn't the name of one of the variables in your template.
So how do we fix this? Well, there are a few alternatives. You have stumbled over a bad one. You have used code like this:
#rows = [ ... ];
This creates #rows an array with a single element which is a reference to your real array. This means that:
$template->param(language => #rows);
is interpreted as:
$template->param(language => $rows[0]);
And as $rows[0] is a reference to your array, it all works.
Far better would be to explicitly pass a reference to #rows.
#rows = ( ... ); # your original version
$template->param(language => \#rows);
Or to create an array reference, stored in a scalar.
$rows = [ ... ];
$template->param(language => $rows);
There's really nothing to choose between these two options.
However, I would ask you to consider why you are spending time teaching yourself HTML::Template. It has been many years since I have seen it being used. The Template Toolkit seems to have become the de-facto standard Perl templating engine.

what does double square brackets mean in swift?

the below is the sample code in swift.
var loadedMessages = [[Message]]()
Message is a custom class. i'm not sure what [[Message]] () is doing.
It is specifying that your variable loadedMessages is an array of arrays that contains Message objects. A JSON representation of loadedMessages might look like:
loadedMessages: [
[ <Message>, <Message>, <Message> ],
[ <Message>, <Message>, <Message> ]
]
A quick Playground implementation of something similar can give you a pretty good introspection of the situation:
var foo = [[String]]()
foo.append(["bar"])
foo[0][0] // reveals "bar"
It means it’s an array of arrays of messages. Think of it in terms of whatever appears between the square brackets being an array of that, and this can include another array.
Alternatively, if you were to write out without the “shorthand” array syntax, it would be Array<Array<Messages>>().

Resources