I have and indexed array that looks like this - drupal-8

$values[0]['myname']['myheight']['height'];
$values[1]['myname']['myheight']['height'];
$values[2]['myname']['myheight']['height'];
$values[3]['myname']['myheight']['height'];
I want to loop through the array to check 'height' and skip through the other values if the are set especially the first key in my $values array.
I tried something like
$values[$key];
if (is_numeric($key) ) {
do this
}
but this doesn't seem to achieve it

Try this
foreach ($value as $key => $val) {
if(isset($val['myname']['myheight']['height'])){
#do this
}
}

Related

Breaking out of loop causes different results [duplicate]

This question already has answers here:
Why doesn't Perl's each() iterate through the entire hash the second time?
(2 answers)
Closed 7 years ago.
I have this code:
#!/usr/bin/perl
use strict;
use warnings;
my $judge_exes = {
"^A" => "foo",
"^B" => "bar",
"^C" => "baz",
};
sub get_judge {
my ($test_id) = #_;
my $exe = undef;
while (my ($regex, $judge) = each %$judge_exes) {
if ($test_id =~ /$regex/) {
$exe = $judge;
last;
}
}
if ($exe) {
return $exe;
} else {
return "Undefined!";
}
}
print get_judge("A1");
print get_judge("B2");
print get_judge("C3");
(ideone: http://ideone.com/slxebG)
I expect to get the output foobarbaz, but I end up getting fooUndefined!baz. However, when I comment out the last statement, I get the correct behavior:
#!/usr/bin/perl
use strict;
use warnings;
my $judge_exes = {
"^A" => "foo",
"^B" => "bar",
"^C" => "baz",
};
sub get_judge {
my ($test_id) = #_;
my $exe = undef;
while (my ($regex, $judge) = each %$judge_exes) {
if ($test_id =~ /$regex/) {
$exe = $judge;
# last;
}
}
if ($exe) {
return $exe;
} else {
return "Undefined!";
}
}
print get_judge("A1");
print get_judge("B2");
print get_judge("C3");
(ideone: http://ideone.com/QJpxbK)
Why is this happening? (I'm on Perl 5.16.2, but the issue is also present on 5.10.1 and whatever ideone is using.)
As far as I understand, last just breaks out of the while loop, which is what I want.
$exe doesn't seem to be an alternative falsey value causing me to hit the wrong if-branch. (I could return early, which would be better, but I still wouldn't understand the cause of this.)
I think I'm dereferencing the hash reference correctly.
I didn't think that regex matching would have any side effects relating to loop termination.
The regexes seem to be matching correctly, since I can actually get them to match appropriately under some circumstances, so I don't think it's an interpolation issue.
I'm not modifying the container that I'm iterating over.
Am I just making some silly non-Perl related mistake?
You have become confused. I am not sure where the confusion lies, but you must be aware that the each operator maintains its state between calls. That means your last inside the while loop won't terminate the iteration. Instead it will continue where it last left off when it is next encountered.
You should also be sparing with double-quotes, as they interpolate any scalar or array variables, or backslashed control characters.
Here is how I suggest that you write your algorithm
#!/usr/bin/perl
use strict;
use warnings;
use 5.010;
my $judge_exes = {
'^A' => 'foo',
'^B' => 'bar',
'^C' => 'baz',
};
say get_judge('A1', $judge_exes);
say get_judge('B2', $judge_exes);
say get_judge('C3', $judge_exes);
say get_judge('D4', $judge_exes);
say get_judge('E5', $judge_exes);
sub get_judge {
my ($test_id, $judges) = #_;
for my $re ( keys %$judges ) {
return 1 if $test_id =~ /$re/;
}
'Undefined!';
}
output
1
1
1
Undefined!
Undefined!
Oh, it looks like the behavior is explained here:
Using keys %hash in scalar context returns the number of keys in the hash and resets the iterator associated with the hash. You may need to do this if you use last to exit a loop early so that when you re-enter it, the hash iterator has been reset.
Wasn't expecting that — I had assumed that each would reset the iterator.

perl split the element of array into another 2D array error

I have an array that contains strings looking like this s1,s2,..
I need to split on "," and have the strings in another 2D array
that's my code
#arr2D;
$i=0;
foreach $a (#array){
$arr2D[$i]= split (/,/,$a);
$i++;
}
//print arr2D content
for ($j=0;$j<scalar #arr;$j++){
print $arr2D[$j][0].$arr2D[$j][1]."\n";
}
the problem is while trying to print arr2D content I got nothing... any suggestion ?
You need to capture the result of the split into an array itself. Notice the additional brackets below. This captures the result into an array and assigns the array reference to $arr2D[$i], thus giving you the 2-D array you desire.
foreach my $elem (#array)
{
$arr2D[$i] = [ split( /,/, $elem ) ];
$i++;
}
Also, you probably want to avoid using $a, since perl treats it specially in too many contexts. Notice I changed its name to $elem above.
Stylistically, you can eliminate the $i and the loop by rewriting this as a map:
#arr2D = map { [ split /,/ ] } #array;
That should work, and it's far more concise.

Removing blank elements from an array

In my Perl code, I am accessing an email. I need to fetch the table in it and parse it into an array.
I did it using:
my #plain = split(/\n/,$plaintext);
However, there are many blank elements in #plain. It has 572 elements and about half of them are empty.
Am I doing anything wrong here? What do I need to add/change in my code to get rid of the blank elements?
grep the output so you only get entries that contain non-whitepace characters.
my #plain = grep { /\S/ } split(/\n/,$plaintext);
The correct way to do it is here from #dave-cross
Quick and dirty if you're not up for fixing your split:
foreach(#plain){
if( ( defined $_) and !($_ =~ /^$/ )){
push(#new, $_);
}
}
edit: how it works
There are going to be more elegant and efficient ways of doing it than the above, but as with everything perl-y tmtowtdi! The way this works is:
Loop through the array #plain, making $_ set to current array element
foreach(#plain){
Check the current element to see if we're interested in it:
( defined $_) # has it had any value assigned to it
!($_ =~ /^$/ ) # ignore those which have been assigned a blank value eg. ''
If the current element passes those checks push it to #new
push(#new, $_);
One line addition is required in your code, and it works
#plain= grep { $_ ne '' } #plain;
Here is what i used, too late but this is good one , can be used in future
$t = "1.2,3.4,3.12,3.18,3.27";
my #to = split(',',$t);
foreach $t ( #to ){
push ( #valid , $t );
}
my $max = (sort { $b <=> $a } #valid)[0];
print $max

How can I determine if a value is in a Perl array?

I'm using this small snippet to determine whether or not a URL is currently being stored in an array:
if( $self->{_local} eq "true" && ! grep {m|^$new_href?$|} #m_href_array ) {
push( #m_href_array, $new_href );
push( #href_array, $new_href );
}
It seems to work but then my code throws an error saying:
Sequence (?$...) not implemented in regex; marked by <-- HERE in m/^javascript:SearchGo(?$ <-- HERE / at C:/Perl/site/lib/ACTC.pm line 152, <> line 1.
Can anyone explain why this is happening?
When searching for a string in an array, you can just use eq, rather than a regular expression:
grep { $_ eq $new_href } #m_href_array
However, if you really do need to use a regular expression (for example you are searching for a string matching a substring in the array, you should always quote the string, so that embedded special characters in your string do not have undesired effects:
grep { /\Q$substr\Esomething_else/ } #array
Moreover, if all you care about is whether the value is there, somewhere, you can short-circuit as soon as you've found a match:
use List::Util 'first';
if (first { $_ eq $new_href } #m_href_array) { ... }
or
use List::MoreUtils 'any';
if (any { $_ eq $new_href } #m_href_array) { ... }
If you're going to be doing a lot of searches, or your array is really long, you can make the process faster still by transforming the array into a hash, so you have O(1) lookups:
my %values_index;
#values_index{#array} = ();
if (exists $values_index{$element}) { ... }
You don't need regexp here. Just use eq:
grep { $_ eq $new_href } #m_href_array
Also it's a good idea to use hash instead of array for faster checking:
my %allready_used_url;
if ( $self->{_local} eq "true" && ! exists $allready_used_url{ $new_href } ) {
$allready_used_url{ $new_href } = 1; ## add url to hash
push( #m_href_array, $new_href );
push( #href_array, $new_href );
}
What do you mean by the ? in $new_href?? Assuming there's a string in $new_href, do you expect the last letter of the string to be optional? That's not how the RE parser reads it.
Looks like the value of $new_herf is javascript:SearchGo( which when substituted in the regex check looks like:
^javascript:SearchGo(?$
which is a broken regex as there is no matching ) for (
You're using the URL as the pattern, and it's not a valid pattern. That's not so bad because there are much better ways to do this. The smart match makes it almost trivial:
use 5.010;
if( $new_href ~~ #urls ) { ... }

Perl regex replacement string special variable

I'm aware of the match, prematch, and postmatch predefined variables. I'm wondering if there is something similar for the evaluated replacement part of the s/// operator.
This would be particularly useful in dynamic expressions so they don't have to be evaluated a 2nd time.
For example, I currently have %regexs which is a hash of various search and replace strings.
Here's a snippet:
while (<>) {
foreach my $key (keys %regexs) {
while (s/$regexs{$key}{'search'}/$regexs{$key}{'replace'}/ee) {
# Here I want to do something with just the replaced part
# without reevaluating.
}
}
print;
}
Is there a convenient way to do it? Perl seems to have so many convenient shortcuts, and it seems like a waste to have to evaluate twice (which appears to be the alternative).
EDIT: I just wanted to give an example: $regexs{$key}{'replace'} might be the string '"$2$1"' thus swapping the positions of some text in the string $regexs{$key}{'search'} which might be '(foo)(bar)' - thus resulting in "barfoo". The second evaluation that I'm trying to avoid is the output of $regexs{$key}{'replace'}.
Instead of using string eval (which I assume is what's going on with s///ee), you could define code references to do the work. Those code references can then return the value of the replacement text. For example:
use strict;
use warnings;
my %regex = (
digits => sub {
my $r;
return unless $_[0] =~ s/(\d)(\d)_/$r = $2.$1/e;
return $r;
},
);
while (<DATA>){
for my $k (keys %regex){
while ( my $replacement_text = $regex{$k}->($_) ){
print $replacement_text, "\n";
}
}
print;
}
__END__
12_ab_78_gh_
34_cd_78_yz_
I'm pretty sure there isn't any direct way to do what you're asking, but that doesn't mean it's impossible. How about this?
{
my $capture;
sub capture {
$capture = $_[0] if #_;
$capture;
}
}
while (s<$regexes{$key}{search}>
<"capture('" . $regexes{$key}{replace}) . "')">eeg) {
my $replacement = capture();
#...
}
Well, except to do it really properly you'd have to shoehorn a little more code in there to make the value in the hash safe inside a singlequotish string (backslash singlequotes and backslashes).
If you do the second eval manually you can store the result yourself.
my $store;
s{$search}{ $store = eval $replace }e;
why not assign to local vars before:
my $replace = $regexs{$key}{'replace'};
now your evaluating once.