Remove elements of a Perl array - arrays

Is there an easy way to remove n consecutive elements of a Perl array (thus making it shorter in length)?

You are looking for the Perl builtin function splice, which lets you pick a starting point, number of elements to remove, and an optional replacement list.
my #array = 0 .. 9;
my #slice = splice #array, 3, 3;
say "#slice"; # prints "3 4 5"
say "#array"; # prints "0 1 2 6 7 8 9"
say 0 + #array; # prints 7

You can use splice to remove array elements.

As the other answers indicated, splice works. As an alternative approach (TIMTOWTDI, after all), if you have the upper and lower indices for the n consecutive elements that you want removed, then you can do it via grep and an array slice. For example:
use strict;
use warnings;
my #a=("a".."z");
#We will remove the letters "e" through "u"
my $lower=4;
my $upper=20;
print "$_\n" foreach(#a[grep{$_<$lower or $_>$upper}0..$#a]);
The output is:
a
b
c
d
v
w
x
y
z

Related

Replicate the array number of times in Perl

I have array which contains 5 elements (1,2,3,4,5). I want to replicate this a number of times based on the value set in the scalar $no_of_replication, e.g. 3.
So that my final array would contain (1,2,3,4,5,1,2,3,4,5,1,2,3,4,5).
Here is what I have tried. It gives me scalar content instead of elements.
use strict;
use warnings;
use Data::Dumper;
my #array = (1,2,3,4,5);
print Dumper(\#array);
my $no_of_replication = 3;
my #new_array = #array * $no_of_replication;
print Dumper(\#new_array);
My array(#new_array) should be like (1,2,3,4,5,1,2,3,4,5,1,2,3,4,5).
The operator for that is x and you need to be careful with the array syntax:
#new_array = ( #array ) x $no_of_replication;
Found the solution here:
Multiplying strings and lists in perl via Archive.org

Perl: equivalent of "ubound" in VBA

Now that on day 2 of Perl I see that arrays start with element(0) too, how do I get the last index of an array like ubound in VBA rather than the size of it using scalar(#array)?
Is the use of $size = $#array a good way or is there something similar to scalar(#array)?
Perl's arrays always start empty.
my #array; # equivalent
my #array = (); #
To get the highest index, use $#array.
my #array = qw(a b c);
print $#array; # 2
If the array is empty, $#array will be -1.

deleting elements in array in a loop Perl

I want to make a loop where I go through all the elements in one array (#array1), and if the same element is found in another array (#array2), I want the value from a third array (#array3) with the same index to be added to the first array and deleted from the third array. I tried it this way, however the line with the if-statement runs on unitialized values, and it loops forever.
foreach my $elem1 (#array1){
my $i = 0;
while ($i < scalar #array2){
if($array2[$i]==$elem1){
push (#array1, $array3[$i]);
delete $array2[$i];
}
else{
$i++;
}
}
}
The problem is you do not increment $i if the element matches. Delete the else.
Well, here's one way to deal with the problem (to the extent that I understand what you want to do). Whenever you need to answer questions about membership, you probably want to use a hash.
use strict;
use warnings;
my #array1 = ( 11, 22, 33, 44);
my #array2 = ( 11, 2, 3, 44, 5, 44);
my #array3 = (-11, -2, -3, -44, -5, -444);
# Keep track of every value in #array1.
my %vals = map { $_ => 1 } #array1;
my #keep_indexes;
# Go through #array2, either adding the corresponding
# value in #array3 to #array1 or storing the array index.
for my $i (0 .. $#array2) {
if ($vals{$array2[$i]}){
push #array1, $array3[$i];
}
else {
push #keep_indexes, $i;
}
}
# Rebuild #array3 from the indexes that we stored.
# Change this to #array2 if you want to delete from that array instead.
#array3 = map $array3[$_], #keep_indexes;
print join(' ', #array1), "\n"; # 11 22 33 44 -11 -44 -444
print join(' ', #array2), "\n"; # 11 2 3 44 5 44
print join(' ', #array3), "\n"; # -2 -3 -5
I dislike that code, so here are a few caveats:
Any time you have numbered variable names (#array1, #array2, etc.), you're headed for confusion. You need better variable names or, more likely, a better data structure.
Any time you find yourself in the business of maintaining parallel arrays, you should consider whether a better data structure would help.
You are deleting an element from array2, not array3 as stated in the question. I think the delete operation sets the array element to undef. The next time around the loop it checks that same element that is now undef against $elem. Hence the error. Then it does he same again and again.

In Perl, how can I create a hash table from two equal length arrays?

I am trying to create a hash from 2 different arrays that are the same length. The elements of the 1st array will be the "keys," and the elements of the second array will be the values.
I tried the following code: FYI: the array "vss" refers to virtual server names, and "vsports" refers to tcp ports.
my %vsnhash;
#vsnhash {#vss} = #vsports;
print Dumper(\%vsnhash);
This works for me as long as all the elements (names) in the 1st array are unique. If they are not, I cannot access all the keys=>values in the hash because of a duplicated key.
How can I create an additional unique "level" or "key" to the hash that I could use to reference the data with duplicate names(or "keys") ?
Any suggestions or alternate solutions would be very helpful.
Thanks
for (my $i = 0; $i < #vss; $i++) {
push (#{$vsnhash->{$vss[$i]}}, $vsports[$i]);
}
Then access each hash key as an array. The array will be the size of the number of key references. There are some examples of that here: Perl data structure traversal -- reference followed key
You can also use each_array from List::MoreUtils:
#!/usr/bin/env perl
use strict; use warnings;
use List::MoreUtils qw( each_array );
my #k = qw(a a b c d d e e f);
my #v = qw(1 2 3 4 5 6 7 8 9);
my %h;
my $it = each_array(#k, #v);
while (my ($k, $v) = $it->()) {
push #{ $h{ $k } }, $v;
}
use YAML;
print Dump \%h;
Output:
---
a:
- 1
- 2
b:
- 3
c:
- 4
d:
- 5
- 6
e:
- 7
- 8
f:
- 9

In Perl, what is the difference between #array[1] and $array[1]?

I have been studying array slices and frankly do not see the difference between choosing #array[1] and $array[1]. Is there a difference?
#!/usr/bin/perl
#array = (1,3);
print "\nPrinting out full array..\#array\n";
print "#array\n";
print "\n";
print "Printing out \#array[1]\n";
print "#array[1]\n";
print "Printing out \$array[1]\n";
print "$array[1]\n";
print "\n\n";
This is a FAQ.
The two forms are likely to work the same way in many contexts (but not all, as you can see from the example in the FAQ), but $array[1] expresses the intent more clearly.
$ and # are called sigils: hear what the sigils tell you
When you see $ you are dealing with a single thing.
When you see # you have a list of things.
#array[ 1 ] is a slice, a list with selected elements from the #array list. You have put only an element in this slice, the second element of #array, but it's a list anyway.
$array[ 1 ] is the second element of the list, a single value, a scalar.
#hash{ 'one', 'two' } is another kind of slice: this time we sliced an hash ( %hash ), obtaining a list with values corresponding to keys one and two.
Where's the difference? Although the difference is thin, you should avoid single element slices when you want a single value. Remember that on the right hand side of an expression, single element slices behave like scalars, but when they are on the left hand side of an expression they become a list assignment: they give list context to the expression.
If still you aren't feeling comfortable with the difference between scalar and list context, please don't use single element slices in order to avoid unexpected results in certain situations ( for instance when using the line input operator < > ).
Check the docs and happy Perl.
You already have your answer from Keith and Marco: # means list, $ means scalar (single value). I have more to add that does not fit in a comment.
You do not notice the difference because you are using a slice of one element. However, try this:
use warnings;
use strict;
use v5.10; # to enable say
my #array = (1 .. 10);
say "#array[2 .. 4]"; # [2,3,4] == "3 4 5"
say "#array[1,4,7]"; # == "2 5 8"
Here's some pointers to your code.
use strict;
use warnings;
There really is no excuse for not using these two. There is hardly any circumstance where it is better -- or easier -- to not use them. This holds especially true when you are experimenting and trying to learn perl.
If you had been using warnings, you would have gotten this additional information:
Scalar value #array[1] better written as $array[1]
Which basically is exactly the answer you have been given here, albeit said in the perl compiler's terse language.
Also, using print the way you do it is hard on the eyes. Make use of perl's flexibility:
#!/usr/bin/perl
use strict;
use warnings;
my #array = (1 .. 10);
print "
Printing out full array..\#array
#array
Printing out \#array[1]
#array[1]
Printing out \$array[1]
$array[1]
";
As you can see, this will print out newlines in a WYSIWYG fashion.
There are two differences:
The «1» is evaluated in list context in the case of the array slice (#foo[1]), but in scalar context in the case of the array indexing ($foo[1]). This has no functional effect.
#foo[1] gives a warning.
Good question - here's some differences:
$a[0] = localtime; print #a; # this prints: Tue Nov 1 18:51:13 2011
#a[0] = localtime; print #a; # this prints the amount of seconds, e.g. 13
$a[0] = grep{}, qw(6 2 8); print #a; # this prints: 3
#a[0] = grep{}, qw(6 2 8); print #a; # this prints: 6
$a[0] = reverse ("a", "b"); print #a; # this prints: ba
#a[0] = reverse ("a", "b"); print #a; # this prints: b
$a[0] = ("a", "b"); print #a; # this prints: b
#a[0] = ("a", "b"); print #a; # this prints: a
It doesn't matter if the slice is [1]. You can create more examples by finding functions that give different results when evaluated in different contexts.
Explanation of the latter (4th) example:
The $ in $a[0] creates a scalar context. The context affects the way the comma operator works, creating different results:
"Binary "," is the comma operator. In scalar context it evaluates its left argument, throws that value away, then evaluates its right argument and returns that value."
http://perldoc.perl.org/perlop.html#Comma-Operator
Hence: b
To understand the line beginning with: #a[0] consider:
($a, $b, $c) = ("a", "b", "c", "d"); # here the "d" is discarded
print $a, $b, $c; # this prints: abc
($a, $b) = ("a", "b", "c"); # here the "c" is discarded
($a) = ("a", "b"); # here the "b" is discarded
($a[0]) = ("a", "b"); # here the "b" is discarded
It would appear that parentheses at the beginning of the line create a list context. This is pretty much what it says at: http://docstore.mik.ua/orelly/perl4/prog/ch02_07.htm
"Assignment to a list of scalars also provides a list context to the righthand side, even if there's only one element in the list"
# at the beginnning of a line also creates a list context:
#a[0] = ("a", "b") means evaluate the RHS in the same way as above i.e. discard the "b"

Resources