Obtain 15 characters from a string that contain less than 15 characters in Perl - perl

I have a sequence and a number representing the location of a residue(character). I want to take 7 residues from each side of the residue. This is the code to do that:
my $seq = substr($sequence, $location-8, 14);
This grabs 7 from each side of the residue. However, there are some sequences where there is less than 7 residues on either side. So when this occurs, I get an error saying:
substr outside of string at test9.pl line 52 (#1) (W substr)(F) You tried to reference a substr() that pointed outside of a string. That is, the absolute value of the offset was larger than the length of the string.
How can I change the empty places and replace them with another letter (X for example).
For example, if there is a sequence
ABCDEFGH
and $location points to D, I need 7 on each side so the result would be:
XXXXABCDEFGHXXX

Expanding on my comment above. I would create a my_substr function that encapsulates the padding and location shift.
my $sequence = "ABCDEFGH";
my $location = 3;
sub my_substr {
my ($seq, $location, $pad_length) = #_;
my $pad = "X"x$pad_length;
return substr("$pad$seq$pad", $location, (2*$pad_length+1));
}
print my_substr($sequence, $location, 7) . "\n";
yields
XXXXABCDEFGHXXX

This is an very verbose answer, but more or less gets you what you want:
use strict;
use warnings;
my $sequence = 'ABCDEFGH';
my $wings = 7;
my $location = index $sequence, 'D';
die "D not found" if $location == -1;
my $start = $location - $wings;
my $length = 1 + 2 * $wings;
my $leftpad = 0;
if ($start < 0) {
$leftpad = -1 * $start;
$start = 0;
}
my $seq = substr($sequence, $start, $length);
$seq = ('X' x $leftpad) . $seq if $leftpad;
my $rightpad = $length - length ($seq);
$seq .= 'X' x $rightpad if $rightpad > 0;
print $seq;
Or to avoid all the extra work, could just create a new $sequence variable containing padding:
my $sequence = 'ABCDEFGH';
my $wings = 7;
my $location = index $sequence, 'D';
die "D not found" if $location == -1;
my $paddedseq = ('X' x $wings) . $sequence . ('X' x $wings);
my $seq = substr($paddedseq, $location, 1 + 2 * $wings);
print $seq;

Related

for loop only runs once PERL, Argument "" isn't numeric in substr

I have a for loop with nested if, else, and elsif statements within. The for loop runs correctly, but it only runs once for some reason. I am looking to count the A's, C's, G's, and T's in a sequence, but I want to count them in two groups - a motif group and a background group. The motif group counts need to be position specific while the background counts do not.
Here is what is contained in my .dna file (a .txt would work fine):
AGGCT
Here is what I have so far:
use strict;
use warnings;
#Upload sequence
print "Please enter the filename of the first sequence data: ";
my $filename1 = <STDIN>;
#Remove newline from file
chomp $filename1;
#Open the file and ignore comment lines
open (FILE, '<', $filename1) or die "Cannot open $filename1.",$!;
my $dna;
for (<FILE>)
{
next if /^#/;
next if /^>/;
$dna .= $_;
}
close FILE;
#Remove white spaces
$dna =~ s/[\s\d]//g;
$dna =~ /./g;
#User specifies motif width
print "Please enter the motif width:\n";
my $width = <STDIN>;
#Remove newline from file
chomp $width;
#Omitting code for non-negative widths to keep this shorter
#Initialize counts and arrays for motif positions
my #motA;
my #motC;
my #motG;
my #motT;
#Define length of motif arrays per width
for(0..($width-1))
{
$motA[$_] = 0;
$motC[$_] = 0;
$motG[$_] = 0;
$motT[$_] = 0;
}
#Initialize background counts
my $bgA = 0;
my $bgC = 0;
my $bgG = 0;
my $bgT = 0;
#Generate random start site in the sequence
#for motif to start from
my $ms = int(rand(((length($dna)+1)-$width)));
#Within a motif, count the bases at the positions
for (my $pos = 0..(length($dna)-1))
{
my $base = substr($dna, $pos, 1);
if ($pos = $ms..($ms + $width))
{
#Add to motif counts
if($base eq 'A')
{
$motA[$pos-$ms] = $motA[$pos-$ms] + 1;
}
elsif($base eq 'C')
{
$motC[$pos-$ms] = $motC[$pos-$ms] + 1;
}
elsif($base eq 'G')
{
$motG[$pos-$ms] = $motG[$pos-$ms] + 1;
}
elsif($base eq 'T')
{
$motT[$pos-$ms] = $motT[$pos-$ms] + 1;
}
}
else
{
#Create background counts
if ($base eq 'A')
{
$bgA = $bgA + 1;
}
elsif ($base eq 'C')
{
$bgC = $bgC + 1;
}
elsif ($base eq 'G')
{
$bgG = $bgG + 1;
}
elsif ($base eq 'T')
{
$bgT = $bgT + 1;
}
}
}
print "A #motA\nC #motC\nG #motG\nT #motT\n\n";
print "bgA = $bgA\n
bgC = $bgC\n
bgG = $bgG\n
bgT = $bgT";
The output looks like this:
Please enter the filename of the first sequence data: sample.dna
Please enter the motif width:
3
Argument "" isn't numeric in substr at line 62, <STDIN> line2.
A 0 1 0
C 0 0 0
G 0 0 0
T 0 0 0
bgA = 0
bgC = 0
bgG = 0
bgT = 0
I know that this is most likely because my $dna or $pos in the line with substr contains the "" (empty string?), but I am unsure how to solve this problem. I thought the initialization of $pos took care of that, but that's why I want to ask the masters to see what to do. I THINK that this will solve the for loop problem as well. As always, any and all help is useful. I appreciate it in advance!
This:
for (my $pos = 0..length($dna))
{
my $base = substr($dna, $pos, 1);
probably is meant to be 0..length($dna)-1 instead?
When $pos is the length, the substring is going to be an empty string.
And that's not the proper syntax for a for loop iterating over a range. It should be
for my $pos (0..length($dna)-1)
This:
if ($pos = $ms..($ms + $width))
if I understand correctly should be
if ($pos >= $ms && $pos < $ms + $width)
What you have is assigning to $pos the result of a flipflop operation, which is not going to be anything useful.
It looks like this:
my $ms = int(rand(((length($dna)+1)-$width)));
should be
my $ms = int(rand(((length($dna))-$width)));
E.g. if the $dna length is 10 and width is 3, you want the possible starting offsets to be 0 through 7, not 0 through 8.
And it looks like your counting within the motif should be using the position within the motif, not $pos; this:
$motA[$pos] = $motA[$pos] + 1;
should be
$motA[$pos-$ms] = $motA[$pos-$ms] + 1;

error of "Use of uninitialized value"

previously I asked about a problem regarding my homework to calculate the alignment score of two protein sequences:
how to pass a variable to different if statement
However, I missed a significant amount of information in the question so I have to rewrite the code.
Now my code is done, but I have a warning as Use of uninitialized value $sequence2_new in split at alignment_sequence.pl line 52. Following this warning, there are numerous warning as Use of uninitialized value in string eq at alignment_sequence.pl line 56.I understand it because I have an uninitialized value, but I can't understand how it is uninitialized. My code is following:
#!/usr/in/perl
use warnings;
use strict;
use feature qw(say);
my $infile1 = "cystic_fibrosis.fasta";
my $inFH1;
unless (open($inFH1, "<", $infile1)){
die join (' ', "Can't open", $infile1, $!)
}
my #seq = <$inFH1>;
close $inFH1;
shift #seq;
my $sequence1 = join("", #seq);
$sequence1 =~ s/\n//g;
#parse the query sequence
my $infile2 = "sequence_collection.fasta";
my $inFH2;
unless (open($inFH2, "<", $infile2)){
die join (' ', "Can't open", $infile2, $!)
}
my $beginning = 1;
my #sequence2;
my $sequence2 = "";
while (my $line = <$inFH2>){
chomp $line;
my $chr = substr($line, 0, 1);
if ($chr ne ">"){
$sequence2 = $sequence2.$line;
}else {
if (! $beginning){
push #sequence2, $sequence2;
$sequence2 = "";
}elsif ($beginning){
$beginning = 0;
}
}
}
close $inFH2;
#parse multiple sequence
my $element = scalar(#sequence2);
for ($a = 0; $a < $element; $a++ ){
my $sequence2_new;
if (length $sequence1 < length $sequence2[$a]){
$sequence2_new = substr ($sequence2[$a], 0, length $sequence1);
}
my #sequence1_new = split('', $sequence1);
my #sequence2_new = split('', $sequence2_new);
my $element_new = scalar(#sequence1_new);
my $num = 0;
for ($b = 0; $b < $element_new; $b++){
if ($sequence1_new[$b] eq $sequence2_new[$b]){
$num++;
}
}
my $score = $num / length $sequence1;
say $sequence1;
say $sequence2[$a];
say "\n";
print "The alignment score is: ";
printf("%.2f", $score);
say "\n\n";
}
The file cystic_fibrosis.fasta contains:
>gi|90421313|ref|NP_000483.3| cystic fibrosis transmembrane conductance regulator [Homo sapiens]
MQRSPLEKASVVSKLFFSWTRPILRKGYRQRLELSDIYQIPSVDSADNLSEKLEREWDRELASKKNPKLI
NALRRCFFWRFMFYGIFLYLGEVTKAVQPLLLGRIIASYDPDNKEERSIAIYLGIGLCLLFIVRTLLLHP
AIFGLHHIGMQMRIAMFSLIYKKTLKLSSRVLDKISIGQLVSLLSNNLNKFDEGLALAHFVWIAPLQVAL
LMGLIWELLQASAFCGLGFLIVLALFQAGLGRMMMKYRDQRAGKISERLVITSEMIENIQSVKAYCWEEA
MEKMIENLRQTELKLTRKAAYVRYFNSSAFFFSGFFVVFLSVLPYALIKGIILRKIFTTISFCIVLRMAV
TRQFPWAVQTWYDSLGAINKIQDFLQKQEYKTLEYNLTTTEVVMENVTAFWEEGFGELFEKAKQNNNNRK
TSNGDDSLFFSNFSLLGTPVLKDINFKIERGQLLAVAGSTGAGKTSLLMVIMGELEPSEGKIKHSGRISF
CSQFSWIMPGTIKENIIFGVSYDEYRYRSVIKACQLEEDISKFAEKDNIVLGEGGITLSGGQRARISLAR
AVYKDADLYLLDSPFGYLDVLTEKEIFESCVCKLMANKTRILVTSKMEHLKKADKILILHEGSSYFYGTF
SELQNLQPDFSSKLMGCDSFDQFSAERRNSILTETLHRFSLEGDAPVSWTETKKQSFKQTGEFGEKRKNS
ILNPINSIRKFSIVQKTPLQMNGIEEDSDEPLERRLSLVPDSEQGEAILPRISVISTGPTLQARRRQSVL
NLMTHSVNQGQNIHRKTTASTRKVSLAPQANLTELDIYSRRLSQETGLEISEEINEEDLKECFFDDMESI
PAVTTWNTYLRYITVHKSLIFVLIWCLVIFLAEVAASLVVLWLLGNTPLQDKGNSTHSRNNSYAVIITST
SSYYVFYIYVGVADTLLAMGFFRGLPLVHTLITVSKILHHKMLHSVLQAPMSTLNTLKAGGILNRFSKDI
AILDDLLPLTIFDFIQLLLIVIGAIAVVAVLQPYIFVATVPVIVAFIMLRAYFLQTSQQLKQLESEGRSP
IFTHLVTSLKGLWTLRAFGRQPYFETLFHKALNLHTANWFLYLSTLRWFQMRIEMIFVIFFIAVTFISIL
TTGEGEGRVGIILTLAMNIMSTLQWAVNSSIDVDSLMRSVSRVFKFIDMPTEGKPTKSTKPYKNGQLSKV
MIIENSHVKKDDIWPSGGQMTVKDLTAKYTEGGNAILENISFSISPGQRVGLLGRTGSGKSTLLSAFLRL
LNTEGEIQIDGVSWDSITLQQWRKAFGVIPQKVFIFSGTFRKNLDPYEQWSDQEIWKVADEVGLRSVIEQ
FPGKLDFVLVDGGCVLSHGHKQLMCLARSVLSKAKILLLDEPSAHLDPVTYQIIRRTLKQAFADCTVILC
EHRIEAMLECQQFLVIEENKVRQYDSIQKLLNERSLFRQAISPSDRVKLFPHRNSSKCKSKPQIAALKEE
TEEEVQDTRL
The file sequence_collection.fasta contains 100 similar blocks:
>gi|1100985|gb|AAC48608.1| CFTR chloride channel [Oryctolagus cuniculus]
MQRSPLEKAGVLSKLFFSWTRPILRKGYRQRLELSDIYQIPSADSADNLSEKLEREWDRELASKKNPKLI
NALRRCFFWRFMFYGIFLYLGEVTKAVQPLLLGRIIASYDPDNKEERSIAIYLGIGLCLLFVVRTLLLHP
AIFGLHHIGMQMRIAMFSLIYKKGLALAHFVWISPLQVTLLMGLLWELLQASAFCGLAFLIVLALVQAGL
GRMMMKYRDQRAGKINERLVITSEMIENIQSVKAYCWEEAMEKMIENLRQTELKLTRKAAYVRYFNSSAF
FFSGFFVVFLSVLPYALTKGIILRKIFTTISFCIVLRMAVTRQFPWAVQTWYDSLGAINKIQDFLQKQEY
KTLEYNLTTTEVVMDNVTAFWEEGFGELFEKAKQNNSDRKISNGDNNLFFSNFSLLGAPVLEDISFKIER
GQLLAVAGSTGAGKTSLLMMITGELEPSEGKIKHSGRISFCSQFSWIMPGTIKENIIFGVSYDEYRYRSV
IKACQLEEDISKFTEKDNTVLGEGGITLSGGQRARISLARAVYKDADLYLLDSPFGYLDVLTEKEIFESC
VCKLMANKTRIMVTSKMEHLKKADKILILHEGSSYFYGTFSELQSLRPDFSSKLMGYDSFDQFSAERRNS
ILTETLRRFSLEGDASVSWNDTRKQSFKQNGELGEKRKNSILNPVNSMRKFSIVLKTPLQMNGIEEDSDA
TIERRLSLVPDSEQGEAILPRSNMINTGPMLQGCRRQSVLNLMTHSVSQGPSIYRRTTTSTRKMSLAPQT
NLTEMDIYSRRLSQESGLEISEEINEEDLKECFIDDVDSIPTVTTWNTYLRYITVHRSLIFVLIWCIVIF
LAEVAASLVVLWLFGNTAPQDKENSTKSGNSSYAVIITNTSSYYFFYIYVGVADTLLALGLFRGLPLVHT
LITVSKILHHKMLHSVLQAPMSTLNTLKAGGILNRFSKDIAILDDLLPLTIFDFIQLLLIVVGAIAVVSV
LQPYIFLATVPVIAAFILLRAYFLHTSQQLKQLESEGRSPIFTHLVTSLKGLWTLRAFGRQPYFETLFHK
ALNLHTANWFLYLSTLRWFQMRIEMIFVLFFIAVAFISILTTGEGEGRVGIILTLAMNIMSTLQWAVNSS
IDVDSLMQSVSRVFMFIDMPTEAKSTKSIKPSSNCQLSKVMIIENQHVKKDDVWPSGGQMTVKGLTAKYI
DSGNAILENISFSISPGQRVGLLGRTGSGKSTLLSAFLRLLSTEGEIQIDGVSWDSITLQQWRKAFGVIP
QKVFIFSGTFRKNLDPYEQWSDQEIWKVADEVGLRSVIEQFPGKLDFVLVDGGYVLSHGHKQLMCLARSV
LSKAKILLLDEPSAHLDPITYQIIRRTLKQAFADCTVILCEHRIEAMLECQRFLVIEENTVRQYESIQKL
LSEKSLFRQAISSSDRAKLFPHRNSSKHKSRPQITALKEEAEEEVQGTRL
Sorry I know it's very redundant. I will greatly appreciate any suggestions.
In this code, you do not assign a value to $sequence2_new when the if condition is false. That means it remains undef.
my $sequence2_new;
if (length $sequence1 < length $sequence2[$a]){
$sequence2_new = substr ($sequence2[$a], 0, length $sequence1);
}
Try assigning a value to it:
my $sequence2_new = '';
if (length $sequence1 < length $sequence2[$a]){
$sequence2_new = substr ($sequence2[$a], 0, length $sequence1);
}

Select minimum value from head and tail of a column - Perl

Following is a code for distance of each residue from the center of mass of a protein.
use strict;
use warnings;
my $chain = 'A';
my $s1 = 0;
my $s2 = 0;
my $s3 = 0;
my $cx=0;
my $cy=0;
my $cz=0;
my #pdb;
while(<>){
my #col = split;
next unless $col[0] eq 'ATOM' and $col[4] eq $chain;
push #pdb, [#col[2,3,5,6,7,8]];
}
for (my $i=0;$i<=$#pdb;$i++){
my($a, $r, $n, $x, $y, $z) = #{$pdb[$i]};
$s1 = $s1+$x;
$cx++;
$s2 = $s2+$y;
$cy++;
$s3 = $s3+$z;
$cz++;
}
my $X = sprintf "%0.3f", $s1/$cx;
my $Y = sprintf "%0.3f", $s2/$cy;
my $Z = sprintf "%0.3f", $s3/$cz;
#distance of every atom from COM.
for my $j(0..$#pdb){
my($a1, $r1, $n1, $x1, $y1, $z1) = #{$pdb[$j]};
my $dist = sprintf "%0.3f", sqrt(($X-$x1)**2 + ($Y-$y1)**2 + ($Z-$z1)**2);
if($a1 eq 'CA'){
&rmin($dist,"\n");
}
}
sub rmin{
my #pdb1 = #_;
print #pdb1;
}
The subroutine rmin printing the distance of each residue from the COM as a column. I need to send the minimum value from the first 10 and last 10 distances into two separate variables. I have tried head and tail commands using backticks:
#res = `head -10` #pdb1
Using List::Util's min and a couple array slices should work:
use List::Util qw(min);
$smallest_of_first_ten = min #pdb1[0 .. 9];
$smallest_of_last_ten = min #pdb1[-10 .. -1];

Perl: subroutine throwing error with $i

Good morning,
I'm having trouble using a subroutine - if I put certain code into the subroutine, it throws an error of "use of uninitialised value $i in array element".
I have a very long script, so I will only post the bit I believe is relevant.
The subroutine I am calling is commented out underneath &exon_positive_strand (saves you scrolling down). When I remove the subroutine and uncomment the code, I get no errors. I can only imagine it is something to do with $i but I don't know what...
Any advice would be greatly appreciated.
Many thanks,
Ellie
my ($value, $col, $col2, $l_o_b, $left, $matchedID, $diff_three_prime, $diff_five_prime, $sequence, #three_prime_ss, #five_prime_ss, #reverse_five, #reverse_three);
my $i = 0;
open (EXONS_five, '>fasta_exons_five_non');
open (EXONS_three, '>fasta_exons_three_non');
foreach my $match(#exonic_matches) { ## works out exon from boundary relative to correct strand direction ##
if ($exon_ID[$i] !~ m/unknown/ && $dupmatches[$i] == 0)
{
$sequence = '';
$value = $exon_ID[$i];
$col = $exon_left{$value};
$col2 = $exon_right{$value};
#three_prime_ss = split(",", $col); ##splits left column into subcolumns
#five_prime_ss = split(",", $col2); ## splits right columnn into subcolumns
#reverse_three = reverse(#three_prime_ss);
#reverse_five = reverse(#five_prime_ss);
shift(#reverse_five);
if ($strands{$value} =~ m/\+/) {
&exon_positive_strand;
# $diff_three_prime = $LBP[$i] - $three_prime_ss[$exons2{$value} - 1]; ## minus numbers denote a difference to the left (i.e. upsteam)
# $diff_five_prime = $LBP[$i] - $five_prime_ss[$exons2{$value} - 1]; ## minus numbers denote a difference to the left (i.e. upsteam)
# $matchedID = $ID{$LBP[$i]};
# if ($diff_three_prime !~ m/\-/ && $diff_three_prime <= 3) {
# $BP{$LBP[$i]} =~ s/\[[ACTG]\]/$ref[$i]/i; ## putting variant into 50BP seq
# $l_o_b = 20;
# ##$right_of_boundary = 3;
# $l_o_b = $l_o_b + $diff_three_prime;
# $left = 51 - $l_o_b;
# $sequence = substr($BP{$LBP[$i]}, $left, 23);
# }
# elsif ($diff_five_prime =~ m/\-/ && $diff_five_prime >= -3) {
# $BP{$LBP[$i]} =~ s/\[[ACTG]\]/$ref[$i]/i; ## putting variant into 50BP seq
# $l_o_b = 3;
# ##$right_of_boundary = 6;
# $l_o_b = $l_o_b + $diff_five_prime;
# $left = 51 - $l_o_b;
# $sequence = substr( $BP{$LBP[$i]}, $left, 9);
}
}
my $seq_length = length($sequence);
if ($seq_length == 9) {
print EXONS_five (">" . "$match_exon{$col_exon_no[$i]}" . "\n", lc($sequence),"\n");
}
elsif ($seq_length == 23) {
print EXONS_three (">" . "$match_exon{$col_exon_no[$i]}" . "\n", lc($sequence),"\n");
}
$i++;
}
close (EXONS_five);
close (EXONS_three);
"Use of uninitialized value in array element" is not an error, it's a warning. Diagnostics can tell you what it means:
(W uninitialized) An undefined value was used as if it were already
defined. It was interpreted as a "" or a 0, but maybe it was a mistake.
To suppress this warning assign a defined value to your variables.
To help you figure out what was undefined, perl will try to tell you the
name of the variable (if any) that was undefined. In some cases it cannot
do this, so it also tells you what operation you used the undefined value
in. Note, however, that perl optimizes your program and the operation
displayed in the warning may not necessarily appear literally in your
program. For example, "that $foo" is usually optimized into "that "
. $foo, and the warning will refer to the concatenation (.) operator,
even though there is no . in your program.
You need to pass the $i variable to the subroutine:
exon_positive_strand($i);
and
sub exon_positive_strand {
my $i = shift;
...

Perl to count current value based on next value

Currently I'm learning Perl and gnuplot. I would like to know how to count certain value based on the next value. For example I have a text file consist of:
#ID(X) Y
1 1
3 9
5 11
The output should show the value of the unknown ID as well. So, the output should show:
#ID(X) Y
1 1
2 5
3 9
4 10
5 11
The Y of ID#2 is based on the following:
((2-3)/(1-3))*1 + ((2-1)/(3-1))*9 which is linear algebra
Y2=((X2-X3)/(X1-X3))*Y1 + ((X2-X1)/(X3-X1)) * Y3
Same goes to ID#5
Currently I have this code,
#! /usr/bin/perl -w
use strict;
my $prev_id = 0;
my $prev_val = 0;
my $next_id;
my $next_val;
while (<>)
{
my ($id, $val) = split;
for (my $i = $prev_id + 1; $i < $next_id; $i++)
{
$val = (($id - $next_id) / ($prev_id - $next_id)) * $prev_val + (($id - $prev_id) / ($next_id - $prev_id)) * $next_val;
printf ("%d %s\n", $i, $val);
}
printf ("%d %s\n", $id, $val);
($prev_val, $prev_id) = ($val, $id);
($next_val, $next_id) = ($prev_val, $prev_id);
}
Your formula seems more complicated than I would expect, given that you are always dealing with integer spacings of 1.
You did not say whether you want to fill gaps for multiple consecutive missing values, but let's assume you want to.
What you do is read in the first line, and say that's the current one and you output it. Now you read the next line, and if its ID is not the expected one, you fill the gaps with simple linear interpolation...
Pseudocode
(currID, currY) = readline()
outputvals( currID, currY )
while lines remain do
(nextID, nextY) = readline()
gap = nextID - currID
for i = 1 to gap
id = currID + i
y = currY + (nextY - currY) * i / gap
outputvals( id, y )
end
(currID, currY) = (nextID, nextY)
end
Sorry for the non-Perl code. It's just that I haven't been using Perl for ages, and can't remember half of the syntax. =) The concepts here are pretty easy to translate into code though.
Using an array may be the way to go. This will also make your data available for further manipulation.
** Caveat: will not work for multiple consecutive missing values of y; see #paddy's answer.
#!/usr/bin/perl
use strict;
use warnings;
my #coordinates;
while (<DATA>) {
my ($x, $y) = split;
$coordinates[$x] = $y;
}
# note that the for loop starts on index 1 here ...
for my $x (1 .. $#coordinates) {
if (! $coordinates[$x]) {
$coordinates[$x] = (($x - ($x + 1)) / (($x - 1) - ($x + 1)))
* $coordinates[$x - 1]
+ (($x - ($x - 1)) / (($x + 1) - ($x - 1)))
* $coordinates[$x + 1];
}
print "$x - $coordinates[$x]\n";
}
__DATA__
1 1
3 9
5 11
You indicated your problem is getting the next value. The key isn't to look ahead, it's to look behind.
my $prev = get first value;
my ($prev_a, $prev_b) = parse($prev);
my $this = get second value;
my ($this_a, $this_b) = parse($this);
while ($next = get next value) {
my ($next_a, $next_b) = parse($next);
...
$prev = $this; $prev_a = $this_a; $prev_b = $this_b;
$this = $next; $this_a = $next_a; $this_b = $next_b;
}
#! /usr/bin/perl -w
use strict;
my #in = (1,9,11);
my #out;
for (my $i = 0; $i<$#in; $i++) {
my $j = $i*2;
my $X1 = $i;
my $X2 = $i+1;
my $X3 = $i+2;
my $Y1 = $in[$i];
my $Y3 = $in[$i+1];
my $Y2 = $Y1*(($X2-$X3)/($X1-$X3))
+ $Y3*(($X2-$X1)/($X3-$X1));
$out[$j] = $in[$i];
$out[$j+1] = $Y2;
}
$out[$#in*2] = $in[$#in];
print (join " ",#out);