How to generate an array with a counter in Perl?

I want to generate a list of unique IDs. Because some of the IDs are duplicates, I need to add a number at the end to make them unique, like so:

ID=exon00001 ID=exon00002 ID=exon00003 ID=exon00004

Here's what I have so far.

 while (loop through the IDs) {
 # if $id is an exon, then increment the counter by one and add it 
 # to the end of the ID
    if ($id =~ m/exon/) {
    my $exon_count = 0;
    my @exon = $exon_count++; #3
    $number = pop @exon; # removes the first element of the list
    $id = $id.$number;
    print $id."/n"
    }
    }

Basically I want to dynamically generate an array with a counter. It's supposed to create an array (1, 2, 3, 4, ... ) for the total number of exons, then remove the elements and add it to the string. This code doesn't work properly. I think there's something wrong with line #3. Do you guys know? Any ideas? thank you

Answers


Is this what you need? The counter needs to retain its value, so you can't keep resetting it as you are:

use v5.10;

my $exon_count = 0;
while( my $id = <DATA> ) {
    chomp $id;
    if( $id =~ m/exon/ ) {
        $id = sprintf "%s.%03d", $id, $exon_count++;
        }
    say $id;
    }

__END__
ID=exon00001
ID=exon00002
ID=exon00003
ID=exon00004

The output looks like:

ID=exon00001.000
ID=exon00002.001
ID=exon00003.002
ID=exon00004.003

If you're on 5.10 or later, you can use state to declare the variable inside the loop but let it keep its value:

use v5.10;

while( my $id = <DATA> ) {
    chomp $id;
    state $exon_count = 0;
    if( $id =~ m/exon/ ) {
        $id = sprintf "%s.%03d", $id, $exon_count++;
        }
    say $id;
    }

I figure you are new to Perl since your code looks like a mishmash of unrelated things that probably do something much different than you think they do. There's a Perl tutorial for biologists, "Unix and Perl". There's also my Learning Perl book.

Joel asked about using a string as the additional tag. That's fine; Perl lets you increment a string, but only on the ranges a-z and A-Z. We can mix numbers and letters by having a numeric tag that we present in base 36:

use v5.10;

use Math::Base36 'encode_base36';

while( my $id = <DATA> ) {
    chomp $id;
    state $exon_count = 30;
    if( $id =~ m/exon/ ) {
        $id = sprintf "%s.%-5s", $id, encode_base36($exon_count++);
        }
    say $id;
    }

Now you have tags like this:

ID=exon00003.1Q   
ID=exon00004.1R   
ID=exon00001.1S   
ID=exon00002.1T   
ID=exon00003.1U   
ID=exon00004.1V   

As noted in my comment, your code does not compile, and does not work. Start by counting the duplicates, then print the correct count of duplicates based on the ids found. Using printf will be suitable for formatting your number.

my %seen;
my @ids = ( bunch of ids );

map $seen{$_}++, @ids;  # count the duplicates

for my $id (keys %seen) {
    for my $num (1 .. $seen{$id}) {
        printf "%s%05d\n", $id, $num;
    }
}

Need Your Help

Direction Flag in x86

assembly x86 microprocessors

I am unable to understand how does the direction flag work in x86. The text in my lectures say that it increments or decrements the source or destination register but that does not make sense with ...

Pivot Cache Type Mismatch error VB.NET Excel

.net vb.net excel pivot-table

Please see bottom edit for where I am currently at, thank you.