i have an array which contents elements in which some elements are similiar under certain conditions (if we detete the "n and p" from the array element then the similiar element can be recognised) . I want to use these similiar element at once while using foreach statement. The array is seen below
my #array = qw(abc_n abc_p gg_n gg_p munday_n_xy munday_p_xy soc_n soc_p);
Order of the array element need not to be in this way always.
i am editing this question again. Sorry if i am not able to deliver the question properly. I have to print a string multiple times in the file with the variable present in the above array . I am just trying to make you understand the question through below code, the below code is not right in any sense .... i m just using it to make you understand my question.
open (FILE, ">" , "test.v");
foreach my $xy (#array){
print FILE "DUF A1 (.pin1($1), .pin2($2));" ; // $1 And $2 is just used to explain that
} // i just want to print abc_n and abc_p in one iteration of foreach loop and followed by other pairs in successive loops respectively
close (FILE);
The result i want to print is as follows:
DUF A1 ( .pin1(abc_n), .pin2(abc_p));
DUF A1 ( .pin1(gg_n), .pin2(gg_p));
DUF A1 ( .pin1(munday_n_xy), .pin2(munday_p_xy));
DUF A1 ( .pin1(soc_n), .pin2(soc_p));
The scripting language used is perl . Your help is really appreciated .
Thank You.!!
Partitioning a data set depends entirely on how data are "similiar under certain conditions."
The condition given is that with removal of _n and _p the "similar" elements become equal (I assume that underscore; the OP says n and p). In such a case one can do
use warnings;
use strict;
use feature 'say';
my #data = qw(abc_n abc_p gg_n gg_p munday_n_xy munday_p_xy soc_n soc_p);
my %part;
for my $elem (#data) {
push #{ $part{ $elem =~ s/_(?:n|p)//r } }, $elem;
}
say "$_ => #{$part{$_}}" for keys %part;
The grouped "similar" strings are printed as a demo since I don't understand the logic of the shown output. Please build your output strings as desired.
If this is it and there'll be no more input to process later in code, nor will there be a need to refer to those common factors, then you may want the groups in an array
my #groups = values %part;
If needed throw in a suitable sorting when writing the array, sort { ... } values %part.
For more fluid and less determined "similarity" try "fuzzy matching;" here is one example.
I tried to split one string and assign an array, and then add http at the start using unshift.
But, I am not getting the desired output. What am I doing wrong here?
use strict;
my $str = 'script.spoken-tutorial.org/index.php/Perl';
my #arr = split (/\//,$str);
print "chekcing the split function:\n #arr\n";
my #newarr = unshift(#arr, 'http://');
print "printing new array: #newarr\n";
the output is:
checking the split function:
script.spoken-tutorial.org index.php Perl
printing new array: 4
Why instead of adding http is it giving number 4 (which is array length)?
This is documented behaviour. From perldoc -f unshift:
unshift ARRAY,LIST
Does the opposite of a shift. Or the opposite of a push, depending on how you look at it. Prepends list to the front of the array and
returns the new number of elements in the array.
See the bolded last part. This means the return value of the function unshift() is the size of the array. Which is what you did.
unshift(#arr, 'http://'); # this returns 4
What you want is to do either
my #newarr = ('http://', #arr);
Or
my #newarr = #arr;
unshift #newarr, 'http://';
I have these sets of arrays which has two elements for each.
#a = ("a", "b");
#i = (1, 2);
#s = ( "\\!", "\?");
How do I make the result such that it'll return
a1!, b2?
And I need them to be a new set of an array like
#new =(a1!,b2?)
I wrote the code for output of the answer
$i = length(#a);
for (0..$1) {
#array = push(#array, #a[$i], #s[$i];
}
print #array;
However, it only returned
syntax error at pra.pl line 10, near "];"
Thank you in advance.
use 5.008;
use List::AllUtils qw(zip_by);
⋮
my #new = zip_by { join '', #_ } \#a, \#i, \#s;
zip_by is a subroutine from the List::AllUtils module on CPAN. So it's not built-in.
use v6;
⋮
my #new = map { .join }, zip #a, #i, #s;
In Perl 6, zip is already part of the standard library. This additionaly solution is here for flavour, it's an opportunity to show off strengths: does the same job, but with less syntax in comparison, and works out of the box.
v6 is not strictly necessary, here I just used it for contrast to indicate the version. But at the beginning of a file it also has the nice property that if you accidentally run Perl 6 code in Perl 5, you'll get a nice error message instead of a cryptic syntax error. Try it! From the use VERSION documentation:
An exception is raised if VERSION is greater than the version of the current Perl
The basic idea you have is good, to iterate simultaneously using index of an array. But the code has many elementary errors and it also doesn't do what the examples show. I suggest to first make a thorough pass through a modern and reputable Perl tutorial.
The examples indicate that you want to concatenate (see . operator) elements at each index
use warnings;
use strict;
use feature 'say';
my #a1 = ('a', 'b');
my #a2 = (1, 2);
my #a3 = ('!', '?');
my #res;
foreach my $i (0..$#a1) {
push #res, $a1[$i] . $a2[$i] . $a3[$i];
}
say for #res;
where $#a1 is the index of the last element of array #a1. This assumes that all arrays are of the same size and that all their elements are defined.
This exact work can be done using map in one statement
my #res = map { $a1[$_] . $a2[$_] . $a3[$_] } 0..$#a1;
with the same, serious, assumptions. Even if you knew they held, do you know for sure, in every run on any data? For a robust approach see the answer by mwp.
There is also each_array from List::MoreUtils, providing a "simultaneous iterator" for all arrays
my $ea = each_array(#a1, #a2, #a3);
my #res;
while ( my ($e1, $e2, $e3) = $ea->() ) {
push #res, $e1 . $e2 . $e3
}
which is really useful for more complex processing.
A quick run through basics
Always have use warnings; and use strict; at the beginning of your programs. They will catch many errors that would otherwise take a lot of time and nerves.
Don't use single-letter variable names. We quickly forget what they meant and the code gets hard to follow, and they make it way too easy to make silly mistakes.
Array's size is not given by length. It is normally obtained using context -- when an array is assigned to a scalar the number of its elements is returned. For iteration over indices there is $#ary, the index of the last element of #ary. Then the list of indices is 0 .. $#ary, using the range (..) operator
The sigil ($, #, %) at the beginning of an identifier (variable name) indicates the type of the variable (scalar, array, hash). An array element is a scalar so it needs $ -- $ary[0]
The push doesn't return array elements but it rather adds to the array in its first argument the scalars in the list that follows.
The print #array; prints array elements without anything between them. When you quote it spaces are added, print "#array\n";. Note the handy feature say though, which adds the new line.
Always use strict; and use warnings; (and use my to declare variables).
You don't need to escape ? and ! in Perl strings, and you can use the qw// quote-like operator to easily build lists of terms.
You are using length(#a) to determine the last index, but Perl array indexes are zero-based, so the last index would actually be length(#a) - 1. (But that's still not right. See the next point...)
To get an array's length in Perl, you want to evaluate it in scalar context. The length function is for strings.
You have not accounted for the situation when the arrays are not all the same length.
You assign the last index to a variable $i, but then you reference the variable $1 on the next line. Those are two different variables.
You are iterating from zero to the last index, but you aren't explicitly assigning the iterator to a variable, and you aren't using the implicit iterator variable ($_).
To get a single array element by index in Perl, the syntax is $a[$i], not #a[$i]. Because you only want a single, scalar value, the expression has to start with the scalar sigil $. (If instead you wanted a list of values from an expression, you would start the expression with the array sigil #.)
push modifies the array given by the first argument, so there's no need to assign the result back to the array in the expression.
You are missing a closing parenthesis in your push expression.
In your same code, you have #new and #array, and you are only adding elements from #a and #s (i.e. you forgot about #i).
You are pushing elements onto the array, but you aren't concatenating them into the desired string format.
Here is a working version of your implementation:
use strict;
use warnings;
use List::Util qw{max};
my #a = ("a", "b");
my #i = ("1", "2");
my #s = ("!", "?");
my #array;
my $length = max scalar #a, scalar #i, scalar #s;
foreach my $i (0 .. $length - 1) {
push #array, ($a[$i] // '') . ($i[$i] // '') . ($s[$i] // '');
}
print #array;
(The // means "defined-or".)
Here's how I might write it:
use strict;
use warnings;
use List::Util qw{max};
my #a = qw/a b/;
my #i = qw/1 2/;
my #s = qw/! ?/;
my #array = map {
join '', grep defined, $a[$_], $i[$_], $s[$_]
} 0 .. max $#a, $#i, $#s;
print "#array\n";
(The $#a means "give me the index of the last element of the array #a.")
use warnings;
use strict;
use Data::Dumper;
my $result = [];
my #a = ("a", "b");
my #i = (1, 2);
my #s = ( "\!", "\?");
my $index = 0;
for my $a ( #a ) {
push( #$result, ($a[$index], $i[$index], $s[$index]) );
$index = $index + 1;
}
print Dumper(#$result);
I'm developing a Perl script and one of the script functions is to detect many lines of data between two terminals and store them in an array. I need to store all lines in an array but to be grouped separately as 1st line in $1 and 2nd in $2 and so on. The problem here is that number of these lines is variable and will change with each new run.
my #statistics_of_layers_var;
for( <ALL_FILE> ) {
#statistics_of_layers_var = ($all_file =~ /(Statistics\s+Of\s+Layers)
(?:(\n|.)*)(Summary)/gm );
print #statistics_of_layers_var;
The given data should be
Statistics Of Layers
Line#1
Line#2
Line#3
...
Summary
How I could achieve it?
You can achieve this without a complicated regular expression. Simply use the range operator (also called flip-flop operator) to find the lines you want.
use strict;
use warnings;
use Data::Printer;
my #statistics_of_layers_var;
while (<DATA>) {
# use the range-operator to find lines with start and end flag
if (/^Statistics Of Layers/ .. /^Summary/) {
# but do not keep the start and the end
next if m/^Statistics Of Layers/ || m/^Summary/;
# add the line to the collection
push #statistics_of_layers_var, $_ ;
}
}
p #statistics_of_layers_var;
__DATA__
Some Data
Statistics Of Layers
Line#1
Line#2
Line#3
...
Summary
Some more data
It works by looking at the current line and flipps the block on and off. If /^Statistics of Layers/ matches the line it will run the block for each following line until the `/^Summary/ matches a line. Because those start and end lines are included we need to skip them when adding lines to the array.
This also works if your file contains multiple intances of this pattern. Then you'd get all of the lines in the array.
Maybe you can try this :
push #statistics_of_layers_var ,[$a] = ($slurp =~ /(Statistics\s+Of\s+Layers)
(?:(\n|.)*)(Summary)/gm );
I've just started using PERL for some scripting i'm doing, having never used it before, and I'm having some trouble getting some values into an array, and calculating the total.
I have a log file that i want to parse, and using a regex, pick up when certain values appear. i want these values added to an array, and then the total calculated at the end.
The file I'm trying to parse looks like
...completed_pop_count: 0
...uncompleted: 0
CALL NEXT
...completed_pop_count: 2
...uncompleted: 0
CALL NEXT
...completed_pop_count: 2
...uncompleted: 3
CALL NEXT
....and carries on
This is what i have so far:
open (my $file, 'test.log');
while (<$file>){
my #array = /.*completed_pop_count: (.*)$/;
print #array;
}
close($file);
The output to this is like
022.....
To me this looks like all the values are in a single element of the array. However I need them to be on separate so that I can calculate the total sum.
If you want to add elements to array, use push #arr, "element".
use List::Util qw(sum);
my #array;
while (<$file>){
push #array, $1 if /.*completed_pop_count: (.*)$/;
}
print "#array\n";
print sum(#array), "\n";