3

I have an array @abc in which I have the values '1234.txt','2345.txt','3456.txt','4567.txt'. I want to get all the numeric values from this array and put them in another array say @xyz. I have the regex to do so but using map function I am not able to get the numeric values in another array. Below code is the snipet of only the section where I am trying the map function:

use strict;
use warnings;

my @abc = ('1234.txt', '2345.txt', '3456.txt', '4567.txt');
foreach my $abc(@abc) {
    my @xyz = map(m/(\d*).txt/, $abc);
    print "@xyz\n";
}

With this code, I am getting below output:

1234
2345
3456
4567

but this is not an array as when I tried changning print "@xyz\n"; to print "$xyz[0]\n"; I am still getting the same output when the output should only be 1234. I guess the output is in the form of string not array.

Can anyone please help in getting these values in an array.

5
  • Try my @xyz = map { /(\d+)\.txt$/ } @abc; instead of the for loop Commented May 23, 2021 at 8:23
  • Thanks for the reply Håkon Hægland . Actually I want to do foreach as I need to print each element of the array @abc later in my code that is why I am using foreach loop. Can you please let me know if by using foreach how can I take all the numeric elements in the array xyz. Commented May 23, 2021 at 8:46
  • You mean something like this ? Commented May 23, 2021 at 8:53
  • @johnIT Both map and for are loops, so you are looping twice around the values, but still just doing them 1 by 1, which is why the output is the same. And you are assigning the array inside the for-loop, so they will not be saved into the array anyway. Commented May 23, 2021 at 10:50
  • You create 4 arrays with one element each Commented May 24, 2021 at 5:44

2 Answers 2

4

The problem is that your array @xyz will only ever contain one value, since your for loop takes one array element at the time. Then you assign the value of a single scalar through a map statement, to an array declared inside the for-loop, which means the array will be out of scope when the loop is done and no values are ever saved between loop iterations.

my @abc = ('1234.txt', '2345.txt', '3456.txt', '4567.txt');
foreach my $abc(@abc) {        # using one array element at the time
    my @xyz = map(m/(\d*).txt/, $abc);    # single string, never saved
    print "@xyz\n";                       # only prints one value
}

Since @xyz only contains one value, it makes no difference if you print the entire array, or just the first element.

If you want this to work, you have to move the array outside the loop, and use push, not assignment = (the latter will overwrite). And remove the map statement, as it is redundant for single strings. Also, put the print statement outside the loop, or we will print some values multiple times.

my @abc = ('1234.txt', '2345.txt', '3456.txt', '4567.txt');
my @xyz;            # declare outside loop
foreach my $abc(@abc) {
    push @xyz, $abc =~ m/(\d*).txt/;
}
print "@xyz\n";     # print only after all values have been collected

But this is not the best way to do it. The for-loop is redundant if we use map. Both for and map loop around the values in a list/array, so doing it twice serves no purpose in this case. The solution, as has already been given by Wes and in comments:

my @abc = ('1234.txt', '2345.txt', '3456.txt', '4567.txt');
my @xyz = map { m/(\d+).txt/ } @abc;
print "@xyz\n";

Also, you should use \d+ when collecting numbers, as otherwise you will get empty string false positives for some strings. For example, the string foo.txt would return the empty string "". If you expect the whole file name to be numbers you should use a beginning-of-line anchor: /^(\d+)\.txt/. Also, period . should be escaped, because it is a regex meta character.

Sign up to request clarification or add additional context in comments.

Comments

2

The problem is that you are using map for each value rather than calling it once, with the entire list. Instead, try this, which will build your @xyz array all at once and leave the four numbers/strings (they'll be strings but perl will convert them to integers if you try to use them as such):

use strict;
use warnings;

my @abc = ('1234.txt', '2345.txt', '3456.txt', '4567.txt');
my @xyz = map(m/(\d*).txt/, @abc);
print "@xyz\n";

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.