What is the difference between push and unshift in Perl? - perl

Can someone please explain why push behaves the way as shown below?
Basically I am trying to print values of an array populated by push as well unshift.
When I try to print array contents populated by push using array indexes, It always prints the element at the top of the array, whereas array populated by unshift prints contents of array based on array index. I don't understand why.
with unshift
#!/usr/bin/perl
#names = ("Abhijit","Royal Enfield","Google");
#numbers=();
$number=1;
$i=0;
foreach $name (#names) {
#print $_ . "\n";
$number=$number+1;
#push(#numbers,($number));
unshift(#numbers,($number));
print("Array size is :" . #numbers . "\n");
$i=$i+1;
print("Individual Elements are:" . #numbers[i] . "\n");
pop(#numbers);
}
rhv:/var/cl_ip_down>./run.sh
Array size is :1
Individual Elements are:2
Array size is :2
Individual Elements are:3
Array size is :3
Individual Elements are:4
without unshift
#!/usr/bin/perl
#names = ("Abhijit","Royal Enfield","Google");
#numbers=();
$number=1;
$i=0;
foreach $name (#names) {
#print $_ . "\n";
$number=$number+1;
push(#numbers,($number));
#unshift(#numbers,($number));
print("Array size is :" . #numbers . "\n");
$i=$i+1;
print("Individual Elements are:" . #numbers[i] . "\n");
}
rhv:/var/cl_ip_down>./run.sh
Array size is :1
Individual Elements are:2
Array size is :2
Individual Elements are:2
Array size is :3
Individual Elements are:2
/without pop/
#!/usr/bin/perl
#names = ("Abhijit","Royal Enfield","Google");
#numbers=();
$number=1;
$i=0;
foreach $name (#names) {
#print $_ . "\n";
$number=$number+1;
#push(#numbers,($number));
unshift(#numbers,($number));
print("Array size is :" . #numbers . "\n");
$i=$i+1;
print("Individual Elements are:" . #numbers[i] . "\n");
#pop(#numbers);
}
rhv:/var/cl_ip_down>./run.sh
Array size is :1
Individual Elements are:2
Array size is :2
Individual Elements are:3
Array size is :3
Individual Elements are:4
with pop
#!/usr/bin/perl
#names = ("Abhijit","Royal Enfield","Google");
#numbers=();
$number=1;
$i=0;
foreach $name (#names) {
#print $_ . "\n";
$number=$number+1;
#push(#numbers,($number));
unshift(#numbers,($number));
print("Array size is :" . #numbers . "\n");
$i=$i+1;
print("Individual Elements are:" . #numbers[i] . "\n");
pop(#numbers);
}
rhv:/var/cl_ip_down>./run.sh
Array size is :1
Individual Elements are:2
Array size is :1
Individual Elements are:3
Array size is :1
Individual Elements are:4

You really should be using use strict; and use warnings; in your code. Having them activated will allow you to identify errors in your code.
Change all instances of the following:
foreach $name (#names) -> for my $i (#names) as you don't do anything with the elements in the #names array.
#numbers[i] -> $numbers[$i] as this is where you've made a not uncommon mistake of using an array slice rather than referring to an array element.
This is not C. Every 'variable' has to have a sigil ($, #, %, &, etc.) in front of it. That i should really be $i.
As for the difference between push and shift, the documentation explains:
perldoc -f push:
push ARRAY,LIST
Treats ARRAY as a stack, and pushes the values of LIST onto the end of ARRAY. The length of ARRAY increases by the length of LIST. ... Returns the number of elements in the array following the completed "push".
perldoc -f unshift:
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.
To put it ASCII-matically...
+---------+ +-----------+ +---------+
<----- | ITEM(S) | -----> | (#) ARRAY | <----- | ITEM(S) | ----->
shift +---------+ unshift +-----------+ push +---------+ pop
^ ^
FRONT END

unshift is used to add a value or values onto the beginning of an array:
Does the opposite of a shift. Or the opposite of a push, depending on how you look at it.
The new values then become the first elements in the array.
push adds elements to the end of an array:
Treats ARRAY as a stack, and pushes the values of LIST onto the end of ARRAY.

This should really be a comment but it is too long for a comment box, so here it is.
If you want to illustrate the difference between unshift and push, the following would suffice:
#!/usr/bin/perl
use strict; use warnings;
my #x;
push #x, $_ for 1 .. 3;
my #y;
unshift #y, $_ for 1 .. 3;
print "\#x = #x\n\#y = #y\n";
Output:
#x = 1 2 3
#y = 3 2 1
Note use strict; protects you against many programmer errors and use warnings; warns you when you use constructs of dubious value. At your level, neither is optional.

Note that
the preallocated array is balanced toward the 0 end of the array (meaning there is more free space at the far end of the list than there is before the list's 0 element). This is done purposely to make pushes more efficient than unshifts.
http://www.perlmonks.org/?node_id=17890
Although lists do quite fine as "Perl is smartly coded because the use of lists as queues was anticipated (Ibid.)".
For comparison, in various JavaScript engines shift/unshift on arrays seems to be significantly slower.

I haven't seen any articulation of what these methods actually do in terms of operational complexity, which is what helped me with conceptualization: quintessentially, I believe it is called "shift" because it actually has to shift all of the n elements in your array to new indices in order to properly update the length property.
push() and pop() use simpler operational complexity. No matter what the number of n values in your array, or your array.length, push or pop will always execute 1 operation. It doesn't need to deal with indexes, it doesn't need to iterate, it only needs to execute one operation, always at the end of the stack, either adding or removing a value and index.
Most importantly, notice when using push/pop, that the other elements in the array are not affected - they are the same values in the same indices of your array. The length of the array is also automatically updated properly to what you'd expect when removing or adding values.
On the other hand, shift() and unshift() not only add or remove, but also have to actually "shift" all of the other elements in your array into different indices. This is more complex and takes more time because the amount of operations is dependent on n, the number of elements in your array, or array.length. For every n+1 larger, it has to do 1 more operation to shift each of the values into the correct index, properly updating the length properly.
Otherwise, if it didn't perform n operations after shift() and move the other elements, you would have no element at index 0, and it wouldn't change the length of your array, would it? We want the length of our arrays to update intuitively, and shift and unshift have to execute more operations to accomplish this.

Related

Why array counter returns a smaller number? [duplicate]

I seem to have come across several different ways to find the size of an array. What is the difference between these three methods?
my #arr = (2);
print scalar #arr; # First way to print array size
print $#arr; # Second way to print array size
my $arrSize = #arr;
print $arrSize; # Third way to print array size
The first and third ways are the same: they evaluate an array in scalar context. I would consider this to be the standard way to get an array's size.
The second way actually returns the last index of the array, which is not (usually) the same as the array size.
First, the second ($#array) is not equivalent to the other two. $#array returns the last index of the array, which is one less than the size of the array.
The other two (scalar #arr and $arrSize = #arr) are virtually the same. You are simply using two different means to create scalar context. It comes down to a question of readability.
I personally prefer the following:
say 0+#array; # Represent #array as a number
I find it clearer than
say scalar(#array); # Represent #array as a scalar
and
my $size = #array;
say $size;
The latter looks quite clear alone like this, but I find that the extra line takes away from clarity when part of other code. It's useful for teaching what #array does in scalar context, and maybe if you want to use $size more than once.
This gets the size by forcing the array into a scalar context, in which it is evaluated as its size:
print scalar #arr;
This is another way of forcing the array into a scalar context, since it's being assigned to a scalar variable:
my $arrSize = #arr;
This gets the index of the last element in the array, so it's actually the size minus 1 (assuming indexes start at 0, which is adjustable in Perl although doing so is usually a bad idea):
print $#arr;
This last one isn't really good to use for getting the array size. It would be useful if you just want to get the last element of the array:
my $lastElement = $arr[$#arr];
Also, as you can see here on Stack Overflow, this construct isn't handled correctly by most syntax highlighters...
To use the second way, add 1:
print $#arr + 1; # Second way to print array size
All three give the same result if we modify the second one a bit:
my #arr = (2, 4, 8, 10);
print "First result:\n";
print scalar #arr;
print "\n\nSecond result:\n";
print $#arr + 1; # Shift numeration with +1 as it shows last index that starts with 0.
print "\n\nThird result:\n";
my $arrSize = #arr;
print $arrSize;
Example:
my #a = (undef, undef);
my $size = #a;
warn "Size: " . $#a; # Size: 1. It's not the size
warn "Size: " . $size; # Size: 2
The “Perl variable types” section of the perlintro documentation contains
The special variable $#array tells you the index of the last element of an array:
print $mixed[$#mixed]; # last element, prints 1.23
You might be tempted to use $#array + 1 to tell you how many items there are in an array. Don’t bother. As it happens, using #array where Perl expects to find a scalar value (“in scalar context”) will give you the number of elements in the array:
if (#animals < 5) { ... }
The perldata documentation also covers this in the “Scalar values” section.
If you evaluate an array in scalar context, it returns the length of the array. (Note that this is not true of lists, which return the last value, like the C comma operator, nor of built-in functions, which return whatever they feel like returning.) The following is always true:
scalar(#whatever) == $#whatever + 1;
Some programmers choose to use an explicit conversion so as to leave nothing to doubt:
$element_count = scalar(#whatever);
Earlier in the same section documents how to obtain the index of the last element of an array.
The length of an array is a scalar value. You may find the length of array #days by evaluating $#days, as in csh. However, this isn’t the length of the array; it’s the subscript of the last element, which is a different value since there is ordinarily a 0th element.
From perldoc perldata, which should be safe to quote:
The following is always true:
scalar(#whatever) == $#whatever + 1;
Just so long as you don't $#whatever++ and mysteriously increase the size or your array.
The array indices start with 0.
and
You can truncate an array down to nothing by assigning the null list () to it. The following are equivalent:
#whatever = ();
$#whatever = -1;
Which brings me to what I was looking for which is how to detect the array is empty. I found it if $#empty == -1;
There are various ways to print size of an array. Here are the meanings of all:
Let’s say our array is my #arr = (3,4);
Method 1: scalar
This is the right way to get the size of arrays.
print scalar #arr; # Prints size, here 2
Method 2: Index number
$#arr gives the last index of an array. So if array is of size 10 then its last index would be 9.
print $#arr; # Prints 1, as last index is 1
print $#arr + 1; # Adds 1 to the last index to get the array size
We are adding 1 here, considering the array as 0-indexed. But, if it's not zero-based then, this logic will fail.
perl -le 'local $[ = 4; my #arr = (3, 4); print $#arr + 1;' # prints 6
The above example prints 6, because we have set its initial index to 4. Now the index would be 5 and 6, with elements 3 and 4 respectively.
Method 3:
When an array is used in a scalar context, then it returns the size of the array
my $size = #arr;
print $size; # Prints size, here 2
Actually, method 3 and method 1 are same.
Use int(#array) as it threats the argument as scalar.
To find the size of an array use the scalar keyword:
print scalar #array;
To find out the last index of an array there is $# (Perl default variable). It gives the last index of an array. As an array starts from 0, we get the size of array by adding one to $#:
print "$#array+1";
Example:
my #a = qw(1 3 5);
print scalar #a, "\n";
print $#a+1, "\n";
Output:
3
3
As numerous answers pointed out, the first and third way are the correct methods to get the array size, and the second way is not.
Here I expand on these answers with some usage examples.
#array_name evaluates to the length of the array = the size of the array = the number of elements in the array, when used in a scalar context.
Below are some examples of a scalar context, such as #array_name by itself inside if or unless, of in arithmetic comparisons such as == or !=.
All of these examples will work if you change #array_name to scalar(#array_name). This would make the code more explicit, but also longer and slightly less readable. Therefore, more idiomatic usage omitting scalar() is preferred here.
my #a = (undef, q{}, 0, 1);
# All of these test whether 'array' has four elements:
print q{array has four elements} if #a == 4;
print q{array has four elements} unless #a != 4;
#a == 4 and print q{array has four elements};
!(#a != 4) and print q{array has four elements};
# All of the above print:
# array has four elements
# All of these test whether array is not empty:
print q{array is not empty} if #a;
print q{array is not empty} unless !#a;
#a and print q{array is not empty};
!(!#a) and print q{array is not empty};
# All of the above print:
# array is not empty

How to make initialized value with in #array in regrep compilation

i try to run this code lines,
#checkpoint = split (/\s+/,$array_lcp[0]);
$i=scalar #checkpoint
print NAME " $checkpoint[0] ";
for ($k=0; $k<=i; $k++)
{
if ($array_ARGVTEMP[$d] =~ m/$checkpoint[$k]/i)
{
#array = split (/\s+/,$array_ARGVTEMP[$d]);
print NAME " $checkpoint[$k]| $k||
$checkpoint[0]||| $checkpoint[1] ||||$checkpoint[2]||||| ";
} }
but in the result warnings, it said that:
"Use of uninitialized value within #checkpoint in regexp compilation at new3.pl line 64 (#2)" and line 64 is " if($array_ARGVTEMP[$d] =~ m/$checkpoint[$k]/i) "
Please help me, Thank you
#checkpoint has $i elements numbered 0 to $i-1, but you're accessing the element at index $i.
for (my $k=0; $k<=$i; $k++)
should be
for (my $k=0; $k<$i; $k++)
Actually, it should be
for my $k (0..$#checkpoints)
Actually, it should be
for my $checkpoint (#checkpoints)
Update The question changed. Originally the loop went to $k<=2 (array size wasn't mentioned), what this answer addressed. The main point remains and now it is clear that the loop goes up to the index equal to the array size, so one past the fence; the limit should be $k < $i. Thus "value of $k for which there is no element" mentioned below is the last one looped over.
The $checkpoint[$k], that draws the warning in the regex, are elements of the array #checkpoint with indices 0, 1, 2 -- what $k is in the loop.
The "uninitialized value within..." means that the array #checkpoint doesn't actually have all those elements, so for a value of $k for which there is no element the regex attempts to retrieve an undefined value and complains.
The first split likely returned fewer than three elements. Print out the #checkpoint to see.
A few more comments
Please always have use warnigs; and use strict; at the beginning of a program
Use lexical filehandles, so open files with open my $name, ... (not open NAME, ...)
To loop over numbers from a range a nice way is
for my $k (0..2) { ... }
(update) ... but the question changed, with the loop (intended to be) over all array elements and then there is no reason to use the index. Iterate directly over elements
foreach my $checkpoint (#checkpoints) { .... }
Whenever you use \s+ for the separator pattern in split most likely you should be using a special pattern ' ', which splits by \s+ and also disregards leading and trailing space.

perl push many array in one array

I have many short array
#seq1 /773..1447/ #seq2 /1 2 1843..1881 1923..2001/
but i use push
push(#add, #seq1);
push(#add, #seq2);
but it shows like it combine all array into one can't get each sub-array any more
/773..1447 1 2 1843..1881 1923..2001/
when i use
$number=#add;
it shows 6, but it should be 2. Can anyone explain the reason and how to change it.
When i use for loop to add each array
for(..){
#temp= split(/,/,$_);
push(#add, \#temp);
}
Then when i print #add; it only shows memory address, How can show all data in #add
This is normal behavior, use reference to #seq1 if you want #add to be two dimensional array,
push(#add, \#seq1);
To print all values in #add you should use Data::Dumper; print Dumper \#add;
The reason is that all parameters get flattened into list when they are pushed into array, so
#a = #b = (1,2);
push(#add, #a, #b);
is same as writing
push(#add, $a[0],$a[1], $b[0],$b[1]);
Check perlref and perllol for reference.
the push command takes an ARRAY and a LIST. It is important to understand what happens here.
The first argument must be an ARRAY, the one you want to push things on. After that it expects a LIST. What this means is that this push statement provides list context to any #seq_n array - and sort of expands the array into separate elements. So all the elements of the #seq_n are being pushed onto your #add.
Since you did not want that to happen, you wanted an array that holds the separate lists - what we call in Perl a List-of-Lists - you actually wanted to push a reference to your #seq_n arrays, using the \ character.
push #add, \#seq_1, \#seq_2, . . . \#seq_n;
Now you have an array that indeed holds references to each $seq_n.
To print them neatly, each sequence on its own line, you could iterate over each
foreach my $seq (#add) {
# $seq holds a reference to a list!
my $string = join " ", #$seq; # the # dereferences the $seq
print $string, "\n";
}
but TIMTOWTDI
print map {(join " ", #$_), "\n"} #add;
Always consider the context in Perl, and try to embrace the charms of join, grep and map.

Perl: Beginner. Which data structure should I use?

Okay, not sure where to ask this, but I'm a beginner programmer, using Perl. I need to create an array of an array, but I'm not sure if it would be better use array/hash references, or array of hashes or hash of arrays etc.
I need an array of matches: #totalmatches
Each match contains 6 elements(strings):
#matches = ($chapternumber, $sentencenumber, $sentence, $grammar_relation, $argument1, $argument2)
I need to push each of these elements into the #matches array/hash/reference, and then push that array/hash/reference into the #totalmatches array.
The matches are found based on searching a file and selecting the strings based on meeting the criteria.
QUESTIONS
Which data structure would you use?
Can you push an array into another array, as you would push an element into an array? Is this an efficient method?
Can you push all 6 elements simultaneously, or have to do 6 separate pushes?
When working with 2-D, to loop through would you use:
foreach (#totalmatches) {
foreach (#matches) {
...
}
}
Thanks for any advice.
Which data structure would you use?
An array for a ordered set of things. A hash for a set of named things.
Can you push an array into another array, as you would push an element into an array? Is this an efficient method?
If you try to push an array (1) into an array (2), you'll end up pushing all the elements of 1 into 2. That is why you would push an array ref in instead.
Can you push all 6 elements simultaneously, or have to do 6 separate pushes?
Look at perldoc -f push
push ARRAY,LIST
You can push a list of things in.
When working with 2-D, to loop through would you use:
Nested foreach is fine, but that syntax wouldn't work. You have to access the values you are dealing with.
for my $arrayref (#outer) {
for my $item (#$arrayref) {
$item ...
}
}
Do not push one array into another array.
Lists just join with each other into a new list.
Use list of references.
#create an anonymous hash ref for each match
$one_match_ref = {
chapternumber => $chapternumber_value,
sentencenumber => $sentencenumber_value,
sentence => $sentence_value,
grammar_relation => $grammar_relation_value,
arg1 => $argument1,
arg2 => $argument2
};
# add the reference of match into array.
push #all_matches, $one_match_ref;
# list of keys of interest
#keys = qw(chapternumber sentencenumber sentence grammer_relation arg1 arg2);
# walk through all the matches.
foreach $ref (#all_matches) {
foreach $key (#keys) {
$val = $$ref{$key};
}
# or pick up some specific keys
my $arg1 = $$ref{arg1};
}
Which data structure would you use?
An array... I can't really justify that choice, but I can't imagine what you would use as keys if you used a hash.
Can you push an array into another array, as you would push an element into an array? Is this an efficient method?
Here's the thing; in Perl, arrays can only contain scalar variables - the ones which start with $. Something like...
#matrix = ();
#row = ();
$arr[0] = #row; # FAIL!
... wont't work. You will have to instead use a reference to the array:
#matrix = ();
#row = ();
$arr[0] = \#row;
Or equally:
push(#matrix, \#row);
Can you push all 6 elements simultaneously, or have to do 6 separate pushes?
If you use references, you need only push once... and since you don't want to concatenate arrays (you need an array of arrays) you're stuck with no alternatives ;)
When working with 2-D, to loop through would you use:
I'd use something like:
for($i=0; $i<#matrix; $i++) {
#row = #{$matrix[$i]}; # de-reference
for($j=0; $j<#row; $j++) {
print "| "$row[$j];
}
print "|\n";
}
Which data structure would you use?
Some fundamental container properties:
An array is a container for ordered scalars.
A hash is a container for scalars obtained by a unique key (there can be no duplicate keys in the hash). The order of values added later is not available anymore.
I would use the same structure like ZhangChn proposed.
Use a hash for each match.
The details of the match then can be accessed by descriptive names instead of plain numerical indices. i.e. $ref->{'chapternumber'} instead of $matches[0].
Take references of these anonymous hashes (which are scalars) and push them into an array in order to preserve the order of the matches.
To dereference items from the data structure
get an item from the array which is a hash reference
retrieve any matching detail you need from the hash reference

Schwartzian transform in Perl?

my #output =
map $_->[0],
sort{$a->[1] <=> $b->[1]}
map [$_,-s $_],
#array;
Can someone explain the code in more detail? I can't get head or tail of it ..
Read from the bottom up:
#array
An array (of filenames, given later usage).
map [$_,-s $_],
For each filename, get a reference to a two element anonymous array, with the first element being the filename and the second element, the byte size of the file. map returns a list of these array references.
sort{$a->[1] <=> $b->[1]}
Sort the list of array references by increasing file size.
map $_->[0],
Turn the list of array references back into a list of filenames, but now in sorted order.
my #output =
Save the list in #output.
This is equivalent in function to:
my #output = sort { -s $a <=> -s $b } #array;
but only gets the size for each file once instead of once per comparison done by the sort.
Wikipedia has a detailed explanation and analysis