Prev | Up | Contents | Down | Next
|
|
From the point of view of a typical University data structure course an array is a data type that contains or stores numbered items sequentially in memory. Each numbered item is called an element of the array, and the number assigned this element is called its index.
In per arrays have a special sigil(the prefix of the name) -- @, For example
my @names= ( 'Nick', 'Tanya', 'Eugenie' );
Like in C the first element has index zero, not one. While array names are prefixed by an @ symbol the elements should be prefixed with $ as they are considered to be scalars. This is an important nuance and the source of constant errors in Perl. for example
print $names[0];
In compiled languages typically all elements of array should have the same type (and thus the same the size in bytes). In this case index is mapped to memory addresses and an increment of the index is the size of the element in bytes.
But Perl arrays are a different and are more common to lists than to arrays in compiled languages like C or Pascal. First because Perl is an untyped language, an element of an array may be of any type, and different elements of the same array may be of different types. Array elements may even contain pointers to other arrays, which allows you to create data structures commonly called "array of arrays."
The second feature of Perl arrays is that they are sparse. This means that array indexes need not fall into a contiguous range of numbers, and that memory is allocated only for those array elements that are actually stored in the array. They are more like an index in the database, or filenames in a directory. Thus, when you assign values only to the first and, say, 1000th elements of an array, Perl will allocate memory only for two elements, not for 1000 elements. In case the elements of the array are strings, another good model of understanding of what Perl array is the buffer of the text editor. Like in text editor you can delete element of array with particular index by "un-defining" them. For example:
$names[2]=undef;
As we already mentioned, it's very important to understand that Perl arrays should be considered not as arrays in compiled languages like Fortran and C, but more like an an attempt to introduce a concept of programmable editor buffer (with indexes as line number) into the programming language. From another point of view of data structures Perl arrays are close to a file directory with numeric file names or to the database of records with numeric key. We will use the terms list and array more or less interchangeably, but there is a small difference between them that we will discuss later.
Perl arrays are always sparse and behave more like a database with numeric keys, then C-style arrays |
Anyway, like in other languages arrays allow to access to their elements by a integer number (index) and like in C the first element of array has index zero. For example the first element of array @names is $names[0], the second element is $names[1], and so on.
Again Perl arrays looks similar to data structures used in sed, vi and other text editors. In Perl we can even count elements from the other end of the array using negative indexes. for example
$names[-1]
is the last element of the array @names. Similarly $names[-2] will the second from the end element of the @names.
In array @week defined as
my @week = ('Mn', 'Ts', 'Wn', 'Th', 'Fr', 'St', 'Sn'); # We use single quote as we do not need any "interpolation"
the element $week[-1] will be 'Sn', element $week[-2] -- 'St' and so on.
Negative indexes are used quite ingeniously in Perl -- as a way of calculating index in the reverse direction. The last element of the array @week is $week[-1], the element before last is $week[-2], etc. This is quite convenient shortcut worth remembering. |
Being actually lists, arrays in Perl have no lower or upper bound and can accept any type of variable (both numbers and strings). . For example:
@workweek = ("Mn", "Ts", "Wn", "Th", "Fr"); # initialization of array @workweek with 5 values @weekend = (6, 7); # another array with just two elements @current = ($today); # an array with just one element
Please note the difference: @current is an array with one element. Variable $today is a scalar. List notation for arrays can be used whenever you can use an array in Perl. Important case is its use of the left side of the assignment statements that we will discuss next.
You can't use non numeric indexes by in Perl you can try and get 'interesting' results: index brackets in Perl enforce conversion to numeric, so $workweek["Mn"] is essentially equal to $workweek[0] . Similarly $workweek["Ts"] is also equivalent to $workweek[0]
Index of the last element of array can always be found using prefix $#. For example for the array $workweek the index of the last element is $#workweek. It also can be accessed as $workweek[-1].
Note: array can contain empty or undef elements. So the index of the last element does not guarantee that all elements exists. It is just a number that is one equal to the maximum index ever used -- it does not tell you how many actual elements are present, only number of "slots" minus one. Total number of slots in the array is one more than the index of the last element. To get it you can assign an array to a scalar variable or use the built-in function scalar.
$days_in_a_week = $#week+1; # will assign the index of the last element incremented by one $days_in_a_week = scalar(@week); # same thing
Please note that the expression ( $#days_in_a_week +1 == scalar($days_in_a_week) ) is always true.
Quotes will turns the list into a string with a space between each element. So they act as an implicit call to the join function, not to the scalar function as you might expect:
$f = "@week"; # result is the sting that contains all elements of @week with delimiter $f=join(' '.@week) # will get yyou the same result # NOTE: the delimiter used is dependent of the value of $" -- default delimiter(usually blank)
Lists in Perl is a notation very similar to arrays. List should be included in parenthesis and should contain zero or more (usually scalar) values separated by comma, for example ("Mn", "Ts", "Wn", "Th", "Fr"). Lists can be assigned to arrays and vise versa (see below). That significantly increase power and flexibility of the language.
Actually list notation for arrays has one difference with an array notation: in a scalar context, array returns the length of the array, but list returns the last value (like the C comma operator), for example.
$last_day = ("Mn", "Ts", "Wn", "Th", "Fr"); # $last_day will be assigned the value "Fr"
List assignment also can be used to assign initial values to several related scalar variables, for example:
($day, $month, $year)=(10,2,2000);
In case of integer arrays, they can be initialized with so called "ranges", for example:
$days_of_the_month=(1..31);
Range operator is more capable then you can assume from this simple example (Adapted from The Range Operator (..))
The range operator is used as a shorthand way to generate arrays. It simplifies the process of creating arrays with contiguous sequences of numbers and letters. We'll start with an array of the numbers one through ten. For example, if we need to create an array with ten elements that include 1, 2, 3, 4, 5, 6, 7, 8, 9, and 10 simply write:
@array = (1..10);
You can also create an array of contiguous letters, for example: an array with ten elements that include A, B, C, D, E, F, G, H, I , and J. is written
@array = ("A".."J");
And, of course, you can have other things in the array definition besides the range operator.
You can create an array that includes AAA, 1, 2, 3, 4, 5, A, B, C, D, and ZZZ by the following
@array = ("AAA", 1..5, "A".."D", "ZZZ");
You can use the range operator to create a list with zero-filled numbers.
To create an array with ten elements that include the strings 01, 02, 03, 04, 05, 06, 07, 08, 09, and 10 do:
@array = ("01".."10");
You can use variables as operands for the range operator. To assign a string literal to $firstVar. Create an array with ten elements that include the strings 01, 02, 03, 04, 05, 06, 07, 08, 09, and 10:
$firstVar = "10"; @array = ("01"..$firstVar);If you use strings of more than one character as operands, the range operator will increment the rightmost character by one and perform the appropriate carry operation when the number 9 or letter z is reached. You'll probably need to see some examples before this makes sense.
You've already seen "A".."Z," which is pretty simple to understand. Perl counts down the alphabet until Z is reached.
Caution should be heeded however: The two ranges "A".."Z" and "a".."Z" are not identical. And the second range does not contain all lowercase letters and all uppercase letters. Instead, Perl creates an array that contains just the lowercase letters. Apparently, when Perl reaches the end of the alphabet-whether lowercase or uppercase-the incrementing stops.
What happens when a two-character string is used as an operand for the range operator? To create an array that includes the strings aa, ab, ac, ad, ae, and af. write:
@array = ("aa" .. "af");
This behaves as you'd expect, incrementing along the alphabet until the f letter is reached. However, if you change the first character of one of the operands, watch what happens.
If we create an array that includes the strings ay, az, ba, bb, bc, bd, be, and bf. we must write:
@array = ("ay" .. "bf");
When the second character is incremented to z, then the first character is incremented to b and the second character is set to a.
Note If the right side of the range operator is greater than the left side, an empty array is created.
Perl provide a set of array operations very similar to PL/1 operations. One unpleasant problem is that the set of array operations is completely different from the set of operations of strings. That's regrettable and complicates the language.
As arrays are actually a text editor buffer Perl provide a pretty rich functionality somewhat similar to the functionality of programmable editors like Sed. First of all you can copy one array to another by simple assignment
@week=@workweek; # buffer to buffer (Select all) copy
What is important that on both sides of the assignment statement one can also use list notation. This way arrays can be used to make multiple assignments to scalar variables and vise versa. This is a very flexible and powerful feature that can be used for transposition of elements, extracting elements from array, etc. For example:
($a, $b) = ($b, $a); # Transposition of $a and $b. It works... ($a, $b) = @week; # $a and $b are the first two elements of @week.
Function splice is very similar to substr and as such is probably the easiest of all array functions to remember and use. It has four forms equivalent to four forms of substr
But semantic unfortunately is different. Unlike substr splice(ARRAY,OFFSET,LENGTH) removes the elements designated by OFFSET and LENGTH from an array. So this is a function with a side effect which changes the value of its first argument.
In list context, it returns the elements removed from the array. In scalar context, returns the last element removed, or undef if no elements are removed.
Like is the case with substr, If OFFSET is negative then it starts that far from the end of the array. If LENGTH is omitted, removes everything from OFFSET onward. If LENGTH is negative, removes the elements from OFFSET onward except for -LENGTH elements at the end of the array. If both OFFSET and LENGTH are omitted, removes everything. If OFFSET is past the end of the array, Perl issues a warning, and splices at the end of the array.
You can also use ranges to generate subset of array.
The push operation make it possible to concatenates arrays with scalars or with arrays. The push build-in function does exactly this:
push(@week, "St", "Sn"); # can add element only to the end (concatenate)
Here is another example when we concatenate two arrays using push:
push(@week, @weekend); # same effect as above
Please not that push modifies the first argument (which should be an array). It does not return a new array as the result. This is yet another Perl idiosyncrasy.
If you want to prepend the array you should use function unshift.
The opposite to the push function is function pop It is an analog of chop function used for strings (but due to, probably questionable decision to permit usage of chop with arrays with different semantic one needs a new name -- here one can see that the possibility to simplify the language by extending semantic of string functions on arrays was missed and this definitely overcomplicates the language).
The function pop removes the last item from a list and return it . Please note that the array size will be truncated by one.
$holiday = pop(@week); # Now $holiday will contain "Sn"
Built-in function pop is extracting the same element as $ARRAY[$#ARRAY].
It is also equivalent to
splice(@a,-1)
If there are no elements in the array, pop returns the undefined value (although this may happen at other times as well). If ARRAY is omitted, pop performs operation on the @ARGV array in the main program, and the @_ array in subroutines, just like shift.
We usually process the array from the beginning and in this case shift function is more convenient than pop. It removes the first element of an array, and return it
shift @week;
The shift function returns the first element of the array and remove it, shortening the array by one. If there are no elements in the array, shift returns the value undef.
The opposite function unshift will add the list supplied as the second argument to the array supplied as the first as the first element of the array:
- unshift ARRAY,LIST
Does the opposite of a shift. Or the opposite of a push, depending on how you look at it. Prepends list to the front of the array and returns the new number of elements in the array.
- unshift(@ARGV, '-e') unless $ARGV[0] =~ /^-/;
Note the LIST is prepended whole, not one element at a time, so the prepended elements stay in the same order. Use reverse to do the reverse.
There is no built-in function for this operation in Perl before 5.10.
Since Perl 5.10 you can use the 'smart-match' operator
~~
,
which returns true if a certain element is contained in an array or hash, and false if it doesn't (see
perlfaq4).
It does not provide the index of the found element. Please be aware that the smart match feature is experimental.
use strict; use v5.10; my @week = ('Mn', 'Ts', 'Wn', 'Th', 'Fr', 'St', 'Sn'); if ( 'St' ~~ @week ) { print "element found\n"; }
Another more complex example, which shows that the left side can be a regular expression:
use strict; use warnings; use 5.010; my @array = qw/aaa bbb/; my $wanted = 'aAa'; say "'$wanted' matches!" if /$wanted/i ~~ @array; # Prints "'aAa' matches!"
If you want to find the first match you can use function first from List::Util which is a standard module included in all Perl distributions. For example
use List::Util 'first';
my $match = first { /pattern/ } @strings
A useful idiom for searching element if you need to find all positions of a given element is slightly perverted usage of grep function:
#!/usr/bin/perl use strict; use warnings; my @x = ( 1, 2, 3, 3, 2, 1, 1, 2, 3, 3, 2, 1 ); my @i = grep { $x[$_] == 3 } 0 .. $#x; print "@i\n";
You can also use firstidx
function from
List::MoreUtils which often is included with
Perl distribution (for example in RHEL) but otherwise needs to be installed from
CPAN:
If you will be doing many searches of the array, AND matching always is defined as string equivalence, then you can normalize your data and use a hash.use strict;
use warnings;
use List::MoreUtils qw(firstidx);
my @nums = ( '830974', '722065', '722046', '716963' );
printf "item with index %i in list is 722065\n", firstidx { $_ eq '722065' } @nums;
__END__item with index 1 in list is 722065
my @strings = qw( aAa Bbb cCC DDD eee ); my %string_lut; # Init via slice: @string_lut{ map uc, @strings } = (); # or use a for loop: # for my $string ( @strings ) { # $string_lut{ uc($string) } = undef; # } #Look for a string: my $search = 'AAa'; print "'$string' ", ( exists $string_lut{ uc $string ? "IS" : "is NOT" ), " in the array\n";
Let me emphasize that doing a hash lookup is good if you are planning on doing many lookups on the array. Also, it will only work
if matching means that $foo eq $bar
, or other requirements that can be met through normalization (like case insensitivity).
See also
How do I search a Perl array for a matching string - Stack Overflow
The function split can be classified as string function, as array function and as the function that can use a regular expression, but we will discuss it as a string function. The function generally accept two arguments: delimiter (which is a regular expression, but we will limit ourselves to strings right now) and target string. For example in Unix colon is a pretty common delimiter for configuration files and we can get elements from the line using split function:
@pass_elems=split(':',pass_line);
Target string or both arguments can be omitted so if $_ contain required string we can write @pass_elems=split(':'). Or if we plan to split on whitespace @pass_lelem=split; At the same time Perl does not understand the notation split(,pass_line); which have a clear semantic meaning -- default delimiter is used. Another similar example:
$_ = "Nick,Tanya,Serg"; @family = split(','); # equal to split(',',$_)
which has the same overall effect as
@family = ("Nick", "Tanya", "Serg");
The default delimiter is whitespace (set of characters that includes blank, tab and newline).
More interesting usage of split is parsing the string into several scalars by using the list notation on the right side of the assignment statement:
$_ = "Nick Tanya Serg"; # a default variable that split operates upon
($husband)=split;
# $husband will contain Nick
($husband, $wife, $child)=split; # all three
We will discuss more complex cases of split in the regular expression chapter. Here is example when you try to process /etc/passwd file:
open(SYSIN,'<','/etc/passwd'); while(<SYSIN> { chomp; $elements=split(':'); }
The default variable $_ is an interesting Perl feature, but it is not implemented uniformly so the code looks a little bit tricky. It is useful and dangerous at the same time because you never know what will change this default variable as there are no strict rules in this regard in Perl and everything is decided on ad hoc basis. So in our case everything is fine:
BTW all Perl input functions put the current line into this variable after reading a record.
The split function can be conveniently used for conversion from strings to arrays and for parsing simple stream of data with fixed delimiter. Please remember that $_ is a default argument and whitespace is a default delimiter.
($username, $uid)=split; # $_ is used as argument and whitespace as a default delimiter ($last_day_of_week)=(split(':',$daylist))[-1]; # if $daylist is "St:Sn" then the last element will be put into $last_day_of_week ($cur_day, @rest_of_the_week) = @week; # here the second element is an array
There is an important nuance in using array in the list notation as in the example above -- array assignments are greedy, so you should never put array name anywhere but the last element of the list:
# @new_week will be assigned all elements from @weeks and the variable # $newday will be left undefined. (@new_week, $lastday) = @week; # most probably this is an error, as variable $lastday will remain undefined.
One important shortcut is the ability of split to convert a string into array of characters. In this case zero length string should be used as the first parameter:
@char=split('',$string);
We will return to this function in regular expressions chapter, but for now please read man page for the function:
Split up a string using a regexp delimiter
split /PATTERN/,EXPR,LIMIT
split /PATTERN/,EXPR
split /PATTERN/
splitSplits a string into an array of strings, and returns it. By default, empty leading fields are preserved, and empty trailing ones are deleted.
If not in list context, returns the number of fields found and splits into the @_ array. (In list context, you can force the split into @_ by using ?? as the pattern delimiters, but it still returns the list value.) The use of implicit split to @_ is deprecated, however, because it clobbers your subroutine arguments.
If EXPR is omitted, splits the $_ string. If PATTERN is also omitted, splits on whitespace (after skipping any leading whitespace). Anything matching PATTERN is taken to be a delimiter separating the fields. (Note that the delimiter may be longer than one character.)
If LIMIT is specified and positive, splits into no more than that many fields (though it may split into fewer). If LIMIT is unspecified or zero, trailing null fields are stripped (which potential users of pop() would do well to remember). If LIMIT is negative, it is treated as if an arbitrarily large LIMIT had been specified.
A pattern matching the null string (not to be confused with a null pattern //, which is just one member of the set of patterns matching a null string) will split the value of EXPR into separate characters at each point it matches that way. For example:
print join(':', split(/ */, 'hi there'));produces the output 'h:i:t:h:e:r:e'.
The LIMIT parameter can be used to split a line partially
($login, $passwd, $remainder) = split(/:/, $_, 3);When assigning to a list, if LIMIT is omitted, Perl supplies a LIMIT one larger than the number of variables in the list, to avoid unnecessary work. For the list above LIMIT would have been 4 by default. In time critical applications it behooves you not to split into more fields than you really need.
If the PATTERN contains parentheses, additional array elements are created from each matching substring in the delimiter.
split(/([,-])/, "1-10,20", 3);produces the list value.
(1, '-', 10, ',', 20)If you had the entire header of a normal Unix email message in $header, you could split it up into fields and their values this way:
$header =~ s/\n\s+/ /g; # fix continuation lines %hdrs = (UNIX_FROM => split /^(\S*?):\s*/m, $header);The pattern /PATTERN/ may be replaced with an expression to specify patterns that vary at runtime. (To do runtime compilation only once, use /$variable/o.)
As a special case, specifying a PATTERN of space (' ') will split on white space just as split() with no arguments does. Thus, split(' ') can be used to emulate awk's default behavior, whereas split(/ /) will give you as many null initial fields as there are leading spaces. A split() on /\s+/ is like a split(' ') except that any leading whitespace produces a null first field. A split() with no arguments really does a split(' ', $_) internally.
Example:
open(PASSWD, '/etc/passwd'); while (<PASSWD>) { ($login, $passwd, $uid, $gid, $gcos, $home, $shell) = split(/:/); #... }
Unpack is probably the second most useful built-in function after splice. Regrettably Perl does not support scanf function from C. Instead it provides similar functionality with unpack. There can be question about introducing a new function instead of tried and true scanf, but again things are already done...
unpack() takes a string and extracts relevant parts of the string into a list, returning an array (in scalar context, it returns the first value produced). Like scanf function in C it uses formatting TEMPLATE. Here I will mention most frequently used formats. See Perl documentation for the complete list:
A An ascii string, truncate trailing spaces from the resulting string a An ascii string, do not truncate trailing spaces from the result x A byte that you need to ignore
When unpacking, "A" strips trailing spaces and nulls, but "a" does not. |
It is interesting to note that one can emulate the substr function with unpack, for example
$word2=substr("Hello world", 6,5); # get the second word $word2=unpack("A6 A5", "Hello world"); # same thingIf you need to extract several words list on the left side of the assignment statement should be used:
#--------------------------12345678901 ($a,$b)=unpack("a5 x1 a5","Hello world");
The same result can be achieved by using
#-----------------------12345678901 ($a,$b)=unpack("A6 A5","Hello world"); # A6 will truncate trailing space
Perl permits generating format string for the pack function dynamically. In case scalar variables are used in the format string they will be interpolated -- one can use scalar variables instead of constant length, for example
($i,$j,$k)=(5,1,5); ($a,$b)=unpack("a$i x$j a$k","Hello world");
Yes it is possible to print content of an array in print statement, but user beware. Since context is important, it shouldn't be too surprising that the following all produce different results:
print @week; # the list will be expanded -- all elements will be printed print "@week"; # guess what will be printed ?Dislaying the number of elecments in the array
print scalar(@week); # classic way of obtaining the number of "slots" int he array. print @#week +1; # same thing via the index of the last element print @week.''; # Slightly pervert way to enforce a scalar context ;-)
print @week+0; # Equivalent to scalar(@week) -- +0 enforces the scalar context ;-)
The way of getting the index of the last element is to use $# prefix, like in the example below:
$last_index = $#array;The last index is one less that the number of elements as indexes are started with zero:
@array = ('1','2') $i= $#array # $i now equals 1 not 2 because it is the index of the last element.Again I would like to remind that scalar(@array) function provide the number of slots (not necessary existing elements) in the array, and prefix $# ( you can consider it to be a function) provides the index of the last element. For example:
for ($i = 0; $i < scalar(@X); $i++) { print $X[$i]; }
The index of the last element of array is always one less than the number of elements, expressions ($#array+1) and scalar(@array) are always equal. |
The scalar built-in function convert its argument into a scalar. Return variable can be not that intuitive -- for example a scalar value of an array is the number of its elements, but never mind.
Again, if the scalar function is supplied with an array argument it returns the number of elements in an array. It just isn't the semantic you would like to expect, but that's how it is. For example:
@X = (1,2,3,4); $X_size = scalar(@X); print $X_size; # will print the number '4'.
Actually operator "<" presuppose scalar on both parts (scalar content in Perl speak) so you can write:
for ($i = 0; $i < @X; $i++) { print $X[$i]; }
This is how loops are usually are written in Perl -- you will see that almost nobody use the scalar function.
For all operations that expect scalar arguments conversion will be performed automatically and you do not need specify function explicitly. For example:
$number_of_elements = @X; # @X in a scalar context...that does not mean that the scalar function should be avoided. It's usage adds clarity to the code.
There are two related functions in Perl grep that resembles Unix grep and map. Both are essentially an shorthand for the foreach loop. Their main value is not a new functionality, but the ability to make the code more compact. Both functions accept two arguments: the first is an expression and the second is the list or array. Both are shorthand for foreach look.
The main difference between them is that grep can just select certain elements from the array or list while map can transform them into a new area.
Suppose we have an array of filenames called @files, and we want a second list called @jpgs containing only those filenames which end in the extension ``.jpg''. Instead of using a loop, we could employ grep as follows:
@jpgs = grep(/\.jpg$/,@files);
As another example, suppose we have a list of files and we want to eliminate all the directories from the list.
@non_a_direcotory = grep(! -d ,@list);
print "Program arguments are:\n", map(" '$_'\n", @ARGV);
It also can simplify creating an array in which each element represents the calue of the function applied to each element of the initial array. Suppose we have a array called @files containing filenames, and we wish to create a similar array called @sizes containing the sizes of those files.
@sizes = map(-s,@files);The same effect can be achieved by:
foreach @files { $sizes($i++)= -s; }
The expression ``-s'', uses $_ as its default argument, so it will return the size of each file in turn. Using map saves shortens the code probably in half and save us from trouble of using explicit iteration counter for the resulting array.
Map often can be used to create a hash in which keys are elements of the array and values is some result of evaluation of each key. For example:
map($sizes{$_} = -s ,@files);In this case, we created the hash %sizes as the expression that we used as the first argument is evaluated once for each element of the array.
You can use a function as the first argument to map, but it should operation on the default variable $_ as the only paramaer, since map does not pass any arguments to a function. If this function is used for other purposes you can simply pass $_ as one of the arguments
See also
The function sort allows you to sort an array using your own comparison routine. For example:
sort (@array); sort { expression } @array); sort sort_function @array;
The default usage of sort is to sort in alphanumeric order. If you wish to to sort the list numerically you might use:
@array Name = sort ($a<=>$b) @array Name; # numeric sort
In this case expression is $a<=>$b is used as comparison function for sort. The sort function should use the special values $a and $b (to denote elements that we compare) and after expression is evaluated should provide just three value -1, 0 or +1. The value of expression is passed to the sorting subroutine.
You can use a function call in place of expression, so sorting can be quite flexible and use for comparison only certain fields instead of all strings $a and $b.
Like in strings this function takes an array, and reverse the order of elements. For example is we have
@week = ("Mn","Ts","Wn","Th","Fr","St","Sn"); # initialization of @week
then we can write
@reversed_week= reverse @week
Although we did not mention it, reverse is also defined on strings, but I was unable to find useful examples to warrant its inclusion in the sting built-in functions section.
The author does not mention a few very useful functions such as glob, which you had to look up elsewhere.
Unfortunately Perl set of functions for manipulating arrays and manipulating strings are unnecessary different and does not exploit similarities inherent in those who data structures.
That greatly complicates learning as the total number of functions a person can remembers is limited and it looks like Perl exceeded this number beyond human capacity with predictable results: nobody is using "full Perl", only a subset, which is manageable for a human.
Each time when I reread this chapter I discover elements that are very useful for me but completely forgotten. That's sad and suggest that the set of built-in functions in Perl is in great need of generalization and simplification.
To get the last element in a list or array, use $array[-1] instead of $array[$#array]. The former works on both lists and arrays, but the latter does not.
There are more then a dozen built-in functions for working with array, functions that are similar to functions designed for working with strings but named differently and sometimes having slightly different semantic.
Internal Links:
External Links:
Will it work or not ?
($first, @rest) = 1 .. Inf;
Would it be better if the type of operation was specified in the operator like in:
We might find some short prefix character stands in for ``list'' or ``scalar''. The obvious candidates are @ and $:
@a $+ @b @a @/ @b
use Tie::CharArray; my $foobar = 'a string'; tie my @foo, 'Tie::CharArray', $foobar; $foo[0] = 'A'; # $foobar = 'A string' push @foo, '!'; # $foobar = 'A string!' print "@foo\n"; # prints: A s t r i n g ! tie my @bar, 'Tie::CharArray::Ord', $foobar; $bar[0]--; # $foobar = '@ string!' pop @bar; # $foobar = '@ string' print "@bar\n"; # prints: 64 32 115 116 114 105 110 103
use Tie::CharArray qw( chars codes ); my $foobar = 'another string'; my $chars = chars $foobar; # arrayref in scalar context push @$chars, '?'; # $foobar = 'another string?' $_ += 2 for codes $foobar; # tied array in list context # $foobar = 'cpqvjgt"uvtkpiA' my @array = chars $foobar; # WARNING: @array isn't tied!
In low-level programming languages such as C, and to some extent Java, strings are not primitive data types, but arrays of characters, which in turn are treated as integers. This closely matches the internal representation of strings in the memory.
Perl, on the other hand, abstracts such internal details away behind the concept of scalars, which can be treated as either strings or numbers, and appear as primitive types to the programmer. This often better matches the way people think about the data.
Sometimes, though, the low-level view is better suited for the task at hand. Perl does offer functions such as ord, chr, pack/unpack and substr that can be used to solve such tasks with reasonable efficiency. For someone used to the direct access to the internal representation offered by other languages, however, these functions may feel awkward. While this is often only a symptom of thinking in un-Perlish terms, sometimes being able to manipulate strings as character arrays really does simplify the code, making the intent more obvious by eliminating syntactic clutter.
This module provides a way to manipulate Perl strings through tied arrays. The operations are implemented in terms of the aforementioned string manipulation functions, but the programmer normally need not be aware of this. As Perl has no primitive character type, two alternative representations are provided:
The first way is to represent characters as strings of length 1. In most cases this is the most convenient representation, as such "characters" can be printed without explicit transformations and written as ordinary Perl string literals.
This representation is provided by the main class Tie::CharArray. As the class maps most array operations directly to calls to substr, several features of that function apply. (Below, @foo is an array tied to Tie::CharArray and $n is a positive integer.)
In general, if you only put one-character strings into the array, and don't go beyond its end, there should be no problems.
While the representation described above is usually the most convenient one, it still does not allow direct arithmetic manipulation of the character code values. For tasks where this is needed, an alternative representation is provided by the subclass Tie::CharArray::Ord. Note that it is perfectly possible to manipulate a single string through both interfaces at the same time. As the array operations are still based on substr(), the first two of the above caveats apply here as well. Unicode support depends on whether and how the underlying perl implementation supports it.
Since using tie() can sometimes seem inconvenient, Tie::CharArray can also export two functions to perform the tying internally. The functions are reproduced below in their entirety.
sub chars ($) { tie my @chars, 'Tie::CharArray', $_[0]; return wantarray ? @chars : \@chars; } sub codes ($) { tie my @codes, 'Tie::CharArray::Ord', $_[0]; return wantarray ? @codes : \@codes; }
When called in scalar context, they return a reference to a tied array through which the characters of the string given to them can be manipulated. In list context the functions return the tied array itself.
This is of rather limited use, since the tied array is only temporary, and assigning it to a permanent array only copies the values it contains but does not tie the permanent array. However, if the temporary array is passed to a subroutine or a foreach loop, Perl will alias the elements directly to the temporary array instead of copying them. What that means in practice is that you can write:
foreach my $ch (chars $string) { # reverse bits in each character $ch = pack "b*", unpack "B*", $ch; }
|
Switchboard | ||||
Latest | |||||
Past week | |||||
Past month |
Google matched content |
Prev | Up | Contents | Down | Next
Society
Groupthink : Two Party System as Polyarchy : Corruption of Regulators : Bureaucracies : Understanding Micromanagers and Control Freaks : Toxic Managers : Harvard Mafia : Diplomatic Communication : Surviving a Bad Performance Review : Insufficient Retirement Funds as Immanent Problem of Neoliberal Regime : PseudoScience : Who Rules America : Neoliberalism : The Iron Law of Oligarchy : Libertarian Philosophy
Quotes
War and Peace : Skeptical Finance : John Kenneth Galbraith :Talleyrand : Oscar Wilde : Otto Von Bismarck : Keynes : George Carlin : Skeptics : Propaganda : SE quotes : Language Design and Programming Quotes : Random IT-related quotes : Somerset Maugham : Marcus Aurelius : Kurt Vonnegut : Eric Hoffer : Winston Churchill : Napoleon Bonaparte : Ambrose Bierce : Bernard Shaw : Mark Twain Quotes
Bulletin:
Vol 25, No.12 (December, 2013) Rational Fools vs. Efficient Crooks The efficient markets hypothesis : Political Skeptic Bulletin, 2013 : Unemployment Bulletin, 2010 : Vol 23, No.10 (October, 2011) An observation about corporate security departments : Slightly Skeptical Euromaydan Chronicles, June 2014 : Greenspan legacy bulletin, 2008 : Vol 25, No.10 (October, 2013) Cryptolocker Trojan (Win32/Crilock.A) : Vol 25, No.08 (August, 2013) Cloud providers as intelligence collection hubs : Financial Humor Bulletin, 2010 : Inequality Bulletin, 2009 : Financial Humor Bulletin, 2008 : Copyleft Problems Bulletin, 2004 : Financial Humor Bulletin, 2011 : Energy Bulletin, 2010 : Malware Protection Bulletin, 2010 : Vol 26, No.1 (January, 2013) Object-Oriented Cult : Political Skeptic Bulletin, 2011 : Vol 23, No.11 (November, 2011) Softpanorama classification of sysadmin horror stories : Vol 25, No.05 (May, 2013) Corporate bullshit as a communication method : Vol 25, No.06 (June, 2013) A Note on the Relationship of Brooks Law and Conway Law
History:
Fifty glorious years (1950-2000): the triumph of the US computer engineering : Donald Knuth : TAoCP and its Influence of Computer Science : Richard Stallman : Linus Torvalds : Larry Wall : John K. Ousterhout : CTSS : Multix OS Unix History : Unix shell history : VI editor : History of pipes concept : Solaris : MS DOS : Programming Languages History : PL/1 : Simula 67 : C : History of GCC development : Scripting Languages : Perl history : OS History : Mail : DNS : SSH : CPU Instruction Sets : SPARC systems 1987-2006 : Norton Commander : Norton Utilities : Norton Ghost : Frontpage history : Malware Defense History : GNU Screen : OSS early history
Classic books:
The Peter Principle : Parkinson Law : 1984 : The Mythical Man-Month : How to Solve It by George Polya : The Art of Computer Programming : The Elements of Programming Style : The Unix Hater’s Handbook : The Jargon file : The True Believer : Programming Pearls : The Good Soldier Svejk : The Power Elite
Most popular humor pages:
Manifest of the Softpanorama IT Slacker Society : Ten Commandments of the IT Slackers Society : Computer Humor Collection : BSD Logo Story : The Cuckoo's Egg : IT Slang : C++ Humor : ARE YOU A BBS ADDICT? : The Perl Purity Test : Object oriented programmers of all nations : Financial Humor : Financial Humor Bulletin, 2008 : Financial Humor Bulletin, 2010 : The Most Comprehensive Collection of Editor-related Humor : Programming Language Humor : Goldman Sachs related humor : Greenspan humor : C Humor : Scripting Humor : Real Programmers Humor : Web Humor : GPL-related Humor : OFM Humor : Politically Incorrect Humor : IDS Humor : "Linux Sucks" Humor : Russian Musical Humor : Best Russian Programmer Humor : Microsoft plans to buy Catholic Church : Richard Stallman Related Humor : Admin Humor : Perl-related Humor : Linus Torvalds Related humor : PseudoScience Related Humor : Networking Humor : Shell Humor : Financial Humor Bulletin, 2011 : Financial Humor Bulletin, 2012 : Financial Humor Bulletin, 2013 : Java Humor : Software Engineering Humor : Sun Solaris Related Humor : Education Humor : IBM Humor : Assembler-related Humor : VIM Humor : Computer Viruses Humor : Bright tomorrow is rescheduled to a day after tomorrow : Classic Computer Humor
The Last but not Least Technology is dominated by two types of people: those who understand what they do not manage and those who manage what they do not understand ~Archibald Putt. Ph.D
Copyright © 1996-2021 by Softpanorama Society. www.softpanorama.org was initially created as a service to the (now defunct) UN Sustainable Development Networking Programme (SDNP) without any remuneration. This document is an industrial compilation designed and created exclusively for educational use and is distributed under the Softpanorama Content License. Original materials copyright belong to respective owners. Quotes are made for educational purposes only in compliance with the fair use doctrine.
FAIR USE NOTICE This site contains copyrighted material the use of which has not always been specifically authorized by the copyright owner. We are making such material available to advance understanding of computer science, IT technology, economic, scientific, and social issues. We believe this constitutes a 'fair use' of any such copyrighted material as provided by section 107 of the US Copyright Law according to which such material can be distributed without profit exclusively for research and educational purposes.
This is a Spartan WHYFF (We Help You For Free) site written by people for whom English is not a native language. Grammar and spelling errors should be expected. The site contain some broken links as it develops like a living tree...
|
You can use PayPal to to buy a cup of coffee for authors of this site |
Disclaimer:
The statements, views and opinions presented on this web page are those of the author (or referenced source) and are not endorsed by, nor do they necessarily reflect, the opinions of the Softpanorama society. We do not warrant the correctness of the information provided or its fitness for any purpose. The site uses AdSense so you need to be aware of Google privacy policy. You you do not want to be tracked by Google please disable Javascript for this site. This site is perfectly usable without Javascript.
Last modified: April 25, 2020