2

I have an array with elements like this:

@ORF= (MEZQFVECQWSXC*FVCXRCT*, MAEZCRTDRX*AZEFZC*AZERC*)

I want to split every array so that each elment starts with 'M' and ends with '*', no extra '*' in between.

so my example above should give me

@ORF = (MEZQFVECQWSXC*,MAEZCRTDRX*)

I thought about first splitting each elements like this:

    foreach (@ORF) {
        my $true= split /\*/, $_;
        push @ORF, $true
}

and then splicing the others out with and if statement, but this does not work.

I also considered using grep

@ORF= grep m/M.*\*/, @ORF;

But this does not affect the array.

I am getting increasingly confused and google is not helping... Please help me out?

1
  • Splice does not work that way, nor does grep. You splice an array using indexes and length, and you grep one list to another list. Read the manual and try again. Commented Nov 17, 2015 at 14:32

3 Answers 3

3

You can indeed do that with split and a loop. You can also use map instead of a for loop.

use strict;
use warnings;
use Data::Printer;

my @ORF= ('MEZQFVECQWSXC*FVCXRCT*', 'MAEZCRTDRX*AZEFZC*AZERC*');
@ORF = map { (split /\*/, $_, 0 )[0] . '*' } @ORF;

p @ORF;

It will iterate over every element in @ORF and split on the *. The 0 as the thrid parameter tells split to only split once. Treat the return value as a list and only take the first element ([0]), put back the asterisk and you've got yourself a new list of strings that start with the M and ends with the asterisk.

[
    [0] "MEZQFVECQWSXC*",
    [1] "MAEZCRTDRX*"
]

Of course that assumes there are only strings that match this pattern without checking.


A simpler way would be to use substr and index to find the first occurance of the * and take the beginning of the string until that character. That's probably more like what you wanted to do with the splice, but misunderstood what that does.

@ORF = map { substr $_, 0 , index($_, '*') + 1 } @ORF;
Sign up to request clarification or add additional context in comments.

2 Comments

Think you can reduce that split to (split /\*/ )[0]
If you use a look-behind assertion, you don't have to add the asterisk again.
2
foreach (@ORF) {
    my $true= split /\*/, $_;
    push @ORF, $true
}

This was actually very close to the solution. There were just a couple of problems.

Firstly, you're assigning the return value from split to a scalar variable. And in scalar context, split returns the number of items it can split the string into, not the items themselves. So you'll just get the value 2. We can fix that by making it a list assignment.

my ($true) = split /\*/, $_;

Secondly, you're pushing your new value on to the end of @ORF. This means that @ORF just keeps getting longer and your loop never ends. You need to replace the current element of the array with your new value. And you can do that by assigning to $_.

So the whole loop becomes:

foreach (@ORF) {
    my ($true) = split /\*/, $_;
    $_ = "$true*";
}

Having said all that, I do prefer simbabque's map solution.

Comments

0

if you like, you could also use map+grep, like so:

use Data::Dumper;

my @ORF= ("MEZQFVECQWSXC*FVCXRCT*", "MAEZCRTDRX*AZEFZC*AZERC*");
@ORF = grep { $_ =~ /^M/ } map { (split/\*/, $_)[0] . '*' } @ORF;
print Data::Dumper->Dump(\@ORF);

Result:

$VAR1 = 'MEZQFVECQWSXC*';
$VAR2 = 'MAEZCRTDRX*';

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.