I have a 3 dimendional array like:
$a[0][0]=1; $a[0][1]=2; $a[0][2]=1;
$a[1][0]=1; $a[1][1]=3; $a[1][2]=-1;
$a[2][0]=2; $a[2][1]=4; $a[2][2]=1;
I would like to erase the line that has as the first two elements the values 1 and 3 (in this case the whole a[1][0 .. 2] elements. The output I would like to obtain is:
$a[0][0]=1; $a[0][1]=2; $a[0][2]=1;
$a[1][0]=2; $a[1][1]=4; $a[1][2]=1;
I am looking for a general solution for this problem. With one condition I would use the grep function, but I don't know how to do it with 2 conditions..
There's no such thing as a 2D array in Perl. #a is just an array of references. So you're not trying to delete $a[1][0 .. 2], but just $a[1].
Yet you can't really delete from an array. Using splice, you can shift all the elements around,
for my $i (reverse 0 .. $#a) {
splice(#a, $i, 1) if $a[$i][0]==1 && $a[$i][1]==3;
}
But it's usually simpler and more efficient to remove the unwanted elements using grep and assigning the rest back to the array.
#a = grep { !( $_->[0]==1 && $_->[1]==3 ) } #a;
use Data::Dumper;
$a[0][0]=1; $a[0][1]=2; $a[0][2]=1;
$a[1][0]=1; $a[1][1]=3; $a[1][2]=-1;
$a[2][0]=2; $a[2][1]=4; $a[2][2]=1;
print Dumper(\#a);
#b=grep(!($_->[0]==1 && $_->[1]==3),#a);
print Dumper(\#b);
Related
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
Let's consider simple Perl code:
my #x = ( 1, 5, 9);
for my $i ( 0 .. $#x ) {
splice( #x, $i, 1 ) if ( $x[$i] >= 5 );
}
print "#x";
Output is not correct, 1 9 but there must be 1
If we run code with -w flag it prints warning
Use of uninitialized value within #x in numeric ge (>=) at splice.pl line 5.
So, it's not good practise to use conditional splice and better to push result in new variable?
The problem isn't your use of conditional splice per se, it's your loop. The most obvious problem, and the one that causes your warning, is that you're running off of the end of the array. for my $i ( 0 .. $#x ) sets the iteration endpoint to $#x before the loop starts, but after you splice one or more elements out, the last index of the array will be smaller. You could fix that using a C-style for loop, instead of the range-style loop, but I don't recommend it — keep reading.
The next problem is that after you splice an element out of the array, you continue the loop with $i one higher... but because you spliced an element out of the array, the next element that you haven't seen yet is in $x[$i], not $x[$i+1]. You say "Output is correct, 1 9", but shouldn't 9 have been removed, since it's more than 5? You could fix this using redo after splice to go through the loop again without incrementing $i, but I don't recommend that either.
So it is possible to fix your loop which uses splice in place so that it will work correctly, but the result would be pretty complicated. Unless there's a compelling reason to do it differently, I would recommend using simply
#x = grep { $_ < 5 } #x;
There's no problem with assigning the result to the same array as the source, and there is no loop management or other housekeeping for you to do.
I have two arrays that I want to compare
#array1 = ( aaa, bbb, aaabbb, aaa23bbb, ddd555, 430hd9789);
#array2 = ( 34322hh2, jjfjr78, uuu7shv, ddd555, hjkdjroo);
I have to compare these two arrays and find duplicate and do something about it.
Conditions:
Length of each element in array can be different. There is no such fixed pattern.
Elements can be just numeric i.e. 334343, or just char i.e. "somewordexample", or it can alphanumeric i.e. wewe83493
There can be more such elements in the array.
Now I know the following about comparison operators == and eq:
== is for comparing numbers
eq is for string comparison
How can I compare alphanumeric values?
This is my code so far
for (my $i = 0 ; $i <= $#array1 ; $i++ ) {
for (my $j = 0 ; $j <= $#array2 ; $j++ ) {
if ( $array1[$i] == $arra2[$j] ) {
print "duplicate";
}
}
}
You manner is indolent, and you seem to be looking for a quick fix without caring whether you understand the solution. The posts on Stack Overflow are primarily for people other than the originator who may have a similar problem.
You should read perlfaq4. Specifically:
perldoc -q intersection - "How do I compute the difference of two arrays? How do I compute the intersection of two arrays?"
perldoc -q contained - "How can I tell whether a certain element is contained in a list or array?"
perldoc -q duplicate - "How can I remove duplicate elements from a list or array?"
Thank you for posting your misbehaving code.
There are a few problems
You must always use strict and use warnings at the top of every Perl program, and declare each variable as close as possible to its first point of use. That simple measure will reveal many faults for you that you may otherwise overlook
I have used qw to define the array data
It is much better to use the Perl foreach than the C-style for
As you appear to have discovered, the == operator is for comparing numbers. You have strings so you need eq
Apart from that, all I have changed in your code is to mention the text of the duplicate entry instead of just printing "duplicate"
use strict;
use warnings;
my #array1 = qw( aaa bbb aaabbb aaa23bbb ddd555 430hd9789 );
my #array2 = qw( 34322hh2 jjfjr78 uuu7shv ddd555 hjkdjroo );
for my $i (0 .. $#array1) {
for my $j (0 .. $#array2) {
if ( $array1[$i] eq $array2[$j] ) {
print "Duplicate '$array1[$i]'\n";
}
}
}
output
Duplicate 'ddd555'
Your alphanumeric values can still be treated as strings. If you want to find elements that are in both your lists, you can use the get_intersection function provided by the List::Compare module:
use strict;
use warnings;
use List::Compare;
my #array1 = qw(aaa bbb aaabbb aaa23bbb ddd555 430hd9789);
my #array2 = qw(34322hh2 jjfjr78 uuu7shv ddd555 hjkdjroo);
my $comp = List::Compare->new(\#array1, \#array2);
my #duplicates = $comp->get_intersection();
if (#duplicates > 0) {
print "#duplicates\n";
}
Output:
ddd555
Alphanumeric values are just strings. Numeric values are a subset of those that Perl considers to be numeric (i.e. Scalar::Util::looks_like_number() returns true). In this case, you could use eq or any other string-related function for comparison (such as the less commonly used index).
To find exact duplicates in O(n) time
my %seen;
for my $duplicate (grep { ++$seen{$_} > 1 } (#array1, #array2))
{
# Do what you need to do to the duplicates
}
If you just want to get rid of the elements of #array1 that are duplicated in #array2,
my %seen = map { $_ => 1 } #array2;
#array1 = grep { not $seen{$_} } #array1;
you can do this using exact matching regex:
if("4lph4" =~ /^4lph4$/)
{ .... }
I have a certain array from which I want to remove the last three element (constant number, because I want a list of subdirectory which are in a directory where there is 3 files).
Is there a better and nicer solution than this one ?
my #list = (`ls --group-directories-first`);
pop #list;
pop #list;
pop #list;
You can use splice:
splice #list, -3;
Where -3 denotes an offset of 3 from the end. This will remove elements from that offset and onward.
It's worth noting that parsing output from ls is a horrible idea. You can do the exact same thing with Perl code:
my #list = grep -d, glob "*";
The -d is a file check, which checks if the current argument is a directory.
splice is also the solution I'd advise.
However, since you're working with the end of an array and just wanting to destroy those trailing elements instead of saving them to another structure, you could also just edit the last array index:
$#list -= 3;
The above is reduces the size of the #list array by 3 elements. Here's another example:
my #a = (1..10);
$#a -= 4;
print "#a\n";
# Prints: 1 2 3 4 5 6
Consider the following code:
my #candidates = get_candidates($marker);
CANDIDATE:
for my $i (0..$#candidates) {
next CANDIDATE if open_region($i);
$candidates[$i] = $incumbent{ $candidates[$i]{region} };
}
What is meaning $# in line 3?
It is a value of last index on array (in your case it is last index on candidates).
Since candidates is an array, $#candidates is the largest index (number of elements - 1)
For example:
my #x = (4,5,6);
print $#x;
will print 2 since that is the largest index.
Note that if the array is empty, $#candidates will be -1
EDIT: from perldoc perlvar:
$# is also used as sigil, which, when prepended on the name of
an array, gives the index of the last element in that array.
my #array = ("a", "b", "c");
my $last_index = $#array; # $last_index is 2
for my $i (0 .. $#array) {
print "The value of index $i is $array[$i]\n";
}
This means array_size - 1. It is the same as (scalar #array) - 1.
In perl ,we have several ways to get an array size ,such as print #arr,print scalar (#arr) ,print $#arr+1 and so on.No reason ,just use it.You will get familiar with some default usage in perl during your further contact with perl .Unlike C++/java ,perl use a lot of
special expression to simplify our coding , but sometimes it always make us more confused.