This is our array :
my #array = ('?C=N;O=D',
'?C=M;O=A',
'?C=S;O=A',
'?C=D;O=A',
'/lab/blog/wp-content/',
'1-list.txt',
'2014/',
'2015/',
'rbxslider/',
'slideshow-gallery/',
'uigen_2015/'
);
how to remove all values before </lab/blog/wp-content/> value
shift #list until (shift (#list)=~m/wp-contnet/);
i have tried with this way but no result
Another way:
#array = grep /wp-content/../(?!)/, #array;
Close.
shift #array until $array[0] =~ /wp-content/;
Or if there's a chance that there might not be anything to remove,
while ($array[0] !~ /wp-content/) { shift #array; }
You might want to make sure you don't loop forever.
while (#array && $array[0] !~ /wp-content/) { shift #array; }
my $count = 0;
my #keep;
foreach (#array){
$count++ if m|/lab/blog/wp-content/|;
push #keep, $_ if $count > 0;
}
say foreach #keep;
/lab/blog/wp-content/
1-list.txt
2014/
2015/
rbxslider/
slideshow-gallery/
uigen_2015/
You're close, when you use the proper array name and correct the typo in "wp-content", but that doesn't include the 'wp-content' element which appears as though you'd like to do. The following checks the first element before shifting, instead of shifting it off and then checking it:
if (grep /wp-content/, #array){
shift #array until $array[0] =~ /wp-content/;
}
print "$_\n" for #array;
Output:
/lab/blog/wp-content/
1-list.txt
2014/
2015/
rbxslider/
slideshow-gallery/
uigen_2015/
Related
I find myself wanting to find the index of the last non-zero element in an array. So, given:
my #array = (0,0,5,9,0,0,0,7,0,3,0,0);
my $indexLastNonZero = insertElegantMethodHere(#array);
# expect $indexLastNonZero to be equal to 9;
I've done this:
for my $i (0 .. $#array) {
$indexLastNonZero = $i if $array[$i] != 0;
};
I works but somehow I can't help feel there must be a super elegant (smarter? nice? more efficient?) way of doing this in perl. I've looked into List::Utils but not found a nice way there and would like a non-core-module independent method.
Any thoughts?
Cheers
Use List::MoreUtils for such tasks:
use warnings;
use strict;
use List::MoreUtils;
my #array = (0,0,5,9,0,0,0,7,0,3,0,0);
print List::MoreUtils::lastidx { $_ } #array
Start at the end of the array and work backwards until you find a non-zero element:
my #array = (0,0,5,9,0,0,0,7,0,3,0,0);
my $i = $#array;
$i-- while $i >= 0 && $array[$i] == 0;
print "The last non-zero element is at index $i\n";
The $i >= 0 test is to guard against the edge case where all elements are zero. In that case the resulting value of $i is -1.
my #array = (0,0,5,9,0,0,0,7,0,3,0,0);
my ($indexLastNonZero) = grep $array[$_], reverse 0 .. $#array;
You could use List::Util, which is in core:
use strict;
use warnings;
use List::Util qw(first);
my #array = (0,0,5,9,0,0,0,7,0,3,0,0);
my $index = #array;
first { $index-- && $_ } reverse #array;
print "Last index that is non-zero: $index\n";
Destructive approach so take a copy of the array first:
my #array2 = #array;
while (!pop #array2) {} # Remove up to and including the last non-zero
print scalar #array2; # Size of remaining elements is index of last non-zero
sub last_true {
pop and return scalar #_ while #_;
undef;
}
my $index = last_true(#foo);
The question is rather vague I know, but I hope the space to explain may help shed light, this is something I've wracked my brain around all day and couldn't find any advice through searching.
Basically I have an array #cluster that I'm trying to use to make an iterator $x skip over the values located in that array. The array will vary in size, so I can't just (rather atrociously) make if statements to fit all cases unfortunately.
Normally when I need to do this with a scalar value I just do:
for my $x (0 .. $numLines){
if($x != $value){
...
}
}
Any advice?
You can do:
my #cluster = (1,3,4,7);
outer: for my $x (0 .. 10){
$x eq $_ and next outer for #cluster;
print $x, "\n";
}
With Perl 5.10 you can also do:
for my $x (0 .. 10){
next if $x ~~ #cluster;
print $x, "\n";
}
or better to use a hash:
my #cluster = (1,3,4,7);
my %cluster = map {$_, 1} #cluster;
for my $x (0 .. 10){
next if $cluster{$x};
print $x, "\n";
}
Hmm... If you are skipping over lines, why not use that criteria directly instead of remembering the lines that need to be filtered out?
The grep function is a powerful construct for filtering lists:
my #array = 1 .. 10;
print "$_\n" for grep { not /^[1347]$/ } #array; # 2,5,6,8,9,10
print "$_\n" for grep { $_ % 2 } #array; # 1,3,5,7,9
my #text = qw( the cat sat on the mat );
print "$_\n" for grep { ! /at/ } #text; # the, on, the
Much less clutter, and much more DWIM!
Dou you mean something like that:
for my $x (0 .. $numLines){
my $is_not_in_claster = 1;
for( #claster ){
if( $x == $_ ){
$is_not_in_claster = 0;
last;
}
}
if( $is_not_in_claster ){
...
}
}
?
Given an array #A we want to check if the element $B is in it. One way is to say this:
Foreach $element (#A){
if($element eq $B){
print "$B is in array A";
}
}
However when it gets to Perl, I am thinking always about the most elegant way. And this is what I am thinking:
Is there a way to find out if array A contains B if we convert A to a variable string and use
index(#A,$B)=>0
Is that possible?
There are many ways to find out whether the element is present in the array or not:
Using foreach
foreach my $element (#a) {
if($element eq $b) {
# do something
last;
}
}
Using Grep:
my $found = grep { $_ eq $b } #a;
Using List::Util module
use List::Util qw(first);
my $found = first { $_ eq $b } #a;
Using Hash initialised by a Slice
my %check;
#check{#a} = ();
my $found = exists $check{$b};
Using Hash initialised by map
my %check = map { $_ => 1 } #a;
my $found = $check{$b};
use 5.10.1;
$B ~~ #A and say '$B in #A';
use List::AllUtils qw/ any /;
print "\#A contains $B" if any { $B eq $_ } #A;
I have an array like ("valueA", "valueB", "valueC", "valueD") etc. I want to loop over the values of the array starting from (for example) the first instance of "valueC". Everything in the array before the first instance of the value "valueC" should be ignored; so in this case only "valueC" and "valueD" would be handled by the loop.
I can just put a conditional inside my loop, but is there a neater way to express the idea using perl?
my $seen;
for ( grep $seen ||= ($_ eq "valueC"), #array ) {
...
}
I think you also need to check if the "valueC" exist inside the array.
Hope this helps.
use strict;
use warnings;
use List::Util qw(first);
my #array = qw(valueA valueB valueC valueD);
my $starting_element = 'valueC';
# make sure that the starting element exist inside the array
# first search for the first occurrence of the $stating_element
# dies if not found
my $starting_index = first { $array[$_] eq $starting_element } 0 .. $#array
or die "element \"$starting_element\" does not exist inside the array";
# your loop
for my $index ($starting_index .. $#array) {
print $array[$index]."\n";
}
my $seen;
for ( #array ) {
$seen++ if /valueC/;
next unless $seen;
...
}
But that $seen is a little ungainly. The flip-flop operator looks tidier IMO:
for ( #array ) {
next unless /^valueC$/ .. /\0/;
# or /^valueC$/ .. '' !~ /^$;
# or $_ eq 'valueC' .. /\0/;
...
}
Or simply (building on ikegami's suggestion):
for ( grep { /^valueC$/ .. /(*FAIL)/ } #array ) { ... }
use List::MoreUtils qw( first_index );
foreach my $item ( #array[ ( first_index { $_ eq 'ValueC' } #array ) .. $#array ] ){
# process $item
}
my $start = 0;
++$start while $start < #array && $array[$start] ne 'valueC';
followed by either
for (#array[$start..$#array]) {
say;
}
or
for my $i ($start..$#array) {
say $array[$i];
}
TIMTOWTDI, but I think that:
foreach my $item (#list) {
next if !$seen && ($item ne 'valueC');
$seen++;
...
}
is both readable, correct and and terse enough. All the /valueC/ solution will process anything after "DooDadvalueCFuBAr", not what the OP asked. And, no you need no flipflop/range operator, and checking for the existence beforehand is really strange, besides requiring a possibly noncore package to perform a rather trivial task.The grep solution is really making my head spin, besides creating and tossing a temp array as a side effect.
If you want to get fancy and avoid ''ifs':
foreach my $item (#list) {
$seen || ($item eq 'valueC') || next;
$seen++;
...
}
Just don't write home about it. :-)
I have some perl code that looks something like this:
my #array = map { rand } ( 1..100 );
my #matching = grep { $_ == $condition } #array;
#array = grep { $_ != $condition } #array;
This works ok, but what I would like to do is split the original array into two based on a single operation...I think I'm carrying out twice as many operations as strictly necessary.
Help appreciated!! Thanks.
This is where part from List::MoreUtils comes in handy.
use List::MoreUtils qw'part';
my($even,$odd) = part { $_ % 2 } #array;
This works great if you want each element of input in exactly one array of the output.
If you want to possibly put them in more than one of the arrays, you have to loop over them yourself.
The best way to do that is with a foreach loop.
my(#div2,#div3);
for my $elem (#array){
push #div2, $elem unless $elem % 2;
push #div3, $elem unless $elem % 3;
}
If there are a lot of similar checks you have to do, perhaps you should loop on what your testing against as-well.
my %div;
for my $elem (#array){
for my $div (2,3,5,7,11,13){
push #{ $out{$div} }, $elem unless $elem % $div;
}
}
By far the easiest method is to iterate your array and push values to either of the two arrays depending on the condition, as in the below example.
for (#array) {
if ($_ % 2) {push #odd, $_}
else {push #even, $_}
}
If you'd like to modify the source array:
for (my $i =0; $i < #array; ++$i) {
if ($array[$i] % 2) {
push #odd, splice (#array, $i--, 1);
}
}
Why didn't you recommend List::MoreUtils::part?
The module in question might not exists on the target system, which is always an annoying thing.
Also on the system I ran tests on I found that List::MoreUtils::part was twice as slow as first snippet in this post, though with different implementations of part it might be the opposite actually.
I love the simplicity of List::MoreUtils' part function:
sub part (&#) {
my ($code, #list) = #_;
my #parts;
push #{ $parts[ $code->($_) ] }, $_ foreach #list;
return #parts;
}
The resulting #parts array is an array of arrayrefs. #$parts[0] is the array of elements that returned false. #$parts[1] returned true.