With apologies if a brief tutorial was not what you wanted...


When to use Hash and Arrays in the program ?

Arrays and Hashes are similar in that they are containers for multiple things (scalars), and you access those things using a form of key. In the case of an Array the key (usually called an index) is an integer -- so  $foo[25] is item 25 in the array @foo. In the case of a Hash the key is a string -- so  $bar{'homburg'} is the homburg item in the hash %bar.

Arrays have an implied ordering: item 0 comes before item 1 and so on. The contents of an array may be treated as a list.

Hashes have no ordering whatsover. So when  keys(%bar) gives you a list of all the keys in the hash, they are in no predictable order -- in particular, not in the order things were put into the hash (except by pure chance) -- this is a common trap that people fall into.

Arrays are used where your key values are simple integers (in a reasonable range), or as containers for lists. For example, the array  @days = ('Mon', 'Tue', 'Wed', 'Thurs', 'Fri', 'Sat', 'Sun') can be accessed by index: $days[4] gives 'Fri', day 4 of the week, where day 0 is 'Mon'. Or treated as a list:  foreach my $d (@days) sets $d to each day name in turn, from 'Mon' to 'Sun'.

Hashes are used where your keys are arbitrary -- noting that the keys you use are converted to strings. For example, the hash  %day_num = ('Mon' => 0, 'Tue' => 1, 'Wed' => 2, 'Thu' => 3, 'Thurs' => 3, 'Fri' => 4, 'Sat' => 5, 'Sun' => 6) can be accessed by the name of a day to get the day number: $day_num{'Thurs'} gives 3. Note that  $day_num{'sat'} will give undef, because there is no such entry -- hashes are very literal minded about the keys. The function exists will tell you whether a given key exists in the hash, so  exists($day_num{'sat'}) would return false, in this case. Other essential functions for using hashes are keys, values and each. You will also find sort used quite a bit with keys, to impose order on chaos.

You can use a Hash to implement a sparse array. So, $sa{79}, $sa{200000}, $sa{123456} could be entries an a sparse array. Noting that the absent entries would all appear as undef. Hash keys are strings, but if you use a number, as above, it will be converted to a string -- Perl is broadminded, and generally does not discriminate between string and numeric values (which has its own little quirks, but that's another story).

This is a big topic. I recommend a little reading !


In which scenario => is used?

As others have said, broadly speaking there is no difference between '=>' and ',' apart from the appearance. I used '=>' between each key and its value in the "literal hash" above. I could just as well have used ',', but the '=>' makes the key/value pairs more obvious.

However, that is not the whole story. Perl has the notion of a "bareword", whose genesis is lost in the mists of time. A bareword is simply a thing that looks like an identifier with no "sigil" (leading '$', '@', '%', ... etc) and no trailing '(). Deciding what a bareword means is a bit of a problem for Perl. If it knows of a subroutine which is defined to take no arguments, Perl will (generally) treat a bareword as a call of that subroutine -- this is how "constants" (as defined by use constant) are implemented. Otherwise Perl either has to know what to do, or must guess. If you use strict (and, frankly, you need a good reason not to), Perl will throw a compile time error rather than guess at the meaning of a bareword.

There are cases where Perl knows what to do with barewords, and hashes are a prime example:

  1. when accessing a hash entry you can write $bar{'homburg'} or $bar{homburg}. Between the '{}' Perl treats a bareword as a literal string. Anything else is treated as an expression, whose result is converted to string form, if required.

    Note that in $spa{0001} the 0001 is not a bareword, it is trivial expression, whose result is converted to the string '1'. So $spa{0001} is not equivalent to $spa{'0001'}, appearance notwithstanding.

  2. this is where '=>' and ',' differ. The '=>' tells Perl to treat any bareword before it as a literal string. So the following are equivalent: ('Mon', 0), ('Mon' => 0) and (Mon => 0).

Note that a bareword is not required in these cases, but if a bareword is present, it is treated as a literal string.

The relationship between "constants" and barewords is slightly tricky. Consider:

use strict; use warnings ; use constant HOMBURG => 'HA' ; my %bar = (homburg => 'homburg!', HOMBURG => 'HomBurg!', HOMBURG, 'H +a!') ; print join(', ', %bar), "\n" ; my $k = HOMBURG ; print "\$k = HOMBURG -> \$k=$k\n" ; print "\$bar{homburg}=$bar{ homburg }, \$bar{HOMBURG}=$bar{HOMBURG}, + ", "\$bar{\$k}=$bar{$k}, \$bar{+HOMBURG}=$bar{+HOMBURG}\n" + ;
whose output is:
  homburg, homburg!, HA, Ha!, HOMBURG, HomBurg!
  $k = HOMBURG  -> $k=HA
  $bar{homburg}=homburg!, $bar{HOMBURG}=HomBurg!, $bar{$k}=Ha!, $bar{+HOMBURG}=Ha!
which shows a number of things:
  1. where Perl is expecting (but not requiring) a bareword, it does not treat the bareword as a "constant". So in HOMBURG => 'HomBurg!' and $bar{HOMBURG} the HOMBURG is not the "constant" whose value is 'HA'. This may or may not be a disappointment.

  2. this special handling means that $bar{HOMBURG} and $bar{$k} are not equivalent, even though HOMBURG has been assigned to $k. (If there wasn't a faint whiff of magic, it wouldn't be Perl.)

  3. if you want the value of the "constant" HOMBURG as a hash key, you need to persuade Perl that there's an expression. In this example I used '+HOMBURG', which is one convention. You could also write $bar{HOMBURG()}, to force Perl to treat it as the subroutine which the "constant" "is" (mostly, but that's another story). Though not shown, the same applies to +HOMBURG => 'Ha!'


If you're still awake, you may be asking yourself why +HOMBURG doesn't generate an error, given that the value of HOMBURG is manifestly not numeric. (The clever people who know the answer to this one can leave now.) So:

Finally, while on the topic of quirks in Perl's handling of strings... when evaluated as a boolean (true/false) value an empty string is false and a non-empty string is considered true, except for '0'. Note that this is not treating the string as a number -- to be false a non-empty string must be exactly one character long, and that character must be '0' ! So:

use strict; use warnings ; foreach my $z ('0', '0000', '+0', '-0', ' 0', '0 ', '0E0') { try($z) + ; } ; sub try { my ($z) = @_ ; my $bool = $z ? 'True' : 'False' ; my $zero = $z == 0 ? '==' : '!=' ; printf "%7s is %5s and %2s 0\n", "'$z'", $bool, $zero ; } ;
gives:
      '0' is False and == 0
   '0000' is  True and == 0
     '+0' is  True and == 0
     '-0' is  True and == 0
     ' 0' is  True and == 0
     '0 ' is  True and == 0
    '0E0' is  True and == 0
You will often see code which tests strings thus:  if ($string). This is shorter than  if ($string ne ''), and has the advantage of working if $string is undef. If $string can ever be '0', however, you will regret not having written  if (defined($string) && ($string ne '')), clumsy though that may appear !


In reply to Re: hash and arrays by gone2015
in thread hash and arrays by sandy_1028

Title:
Use:  <p> text here (a paragraph) </p>
and:  <code> code here </code>
to format your post, it's "PerlMonks-approved HTML":



  • Posts are HTML formatted. Put <p> </p> tags around your paragraphs. Put <code> </code> tags around your code and data!
  • Titles consisting of a single word are discouraged, and in most cases are disallowed outright.
  • Read Where should I post X? if you're not absolutely sure you're posting in the right place.
  • Please read these before you post! —
  • Posts may use any of the Perl Monks Approved HTML tags:
    a, abbr, b, big, blockquote, br, caption, center, col, colgroup, dd, del, details, div, dl, dt, em, font, h1, h2, h3, h4, h5, h6, hr, i, ins, li, ol, p, pre, readmore, small, span, spoiler, strike, strong, sub, summary, sup, table, tbody, td, tfoot, th, thead, tr, tt, u, ul, wbr
  • You may need to use entities for some characters, as follows. (Exception: Within code tags, you can put the characters literally.)
            For:     Use:
    & &amp;
    < &lt;
    > &gt;
    [ &#91;
    ] &#93;
  • Link using PerlMonks shortcuts! What shortcuts can I use for linking?
  • See Writeup Formatting Tips and other pages linked from there for more info.