Beefy Boxes and Bandwidth Generously Provided by pair Networks
Welcome to the Monastery
 
PerlMonks  

Short version of database push for multiple variables

by Anonymous Monk
on May 13, 2012 at 15:07 UTC ( #970291=perlquestion: print w/ replies, xml ) Need Help??
Anonymous Monk has asked for the wisdom of the Perl Monks concerning the following question:

Dear Monks,

I am parsing a tab delimited file. For each row I have 20+ variables. Some of them might be blank. For each variable I want to check if they are present; if so append them to corresponding list if not append "NA" to list. This is quite easy but require 20 if/else loops. Any idea on how to shorten it? Switch will help a bit but I was wondering if there is a way I can do in couple of lines. Simple short example below. Thanks for help!

($a, $b, $c, $d, $e, $f, $g) = split(/\t/, $Line); if ($a =~ /([A-Za-z0-9-_]+)/) { push(@a, $a); } else { push(@a, "NA"); } and 19 more

Comment on Short version of database push for multiple variables
Download Code
Re: Short version of database push for multiple variables
by ww (Bishop) on May 13, 2012 at 16:03 UTC

    Surely, before long, a wiser head will offer the algorithm which (may) have passed thru my brain (and out my ears) when I read your question.

    But, meantime, the code below seems minimally shorter (fewer chars to type, I think) and perhaps at least as clear to a later maintainer... since the test here is not against a particular charset, but rather a test of definedness.

    my @array; my ($a, $b, $c); $a = "foo"; $c = "bar"; if ($a) { # could also be written "if ( defined($a) ) {" push @array, $a; } else { $a = "NA"; push @array, $a; } if ($b) { push @array, $b; } else { $b = "NA"; push @array, $b; } if ($c) { push @array, $c; } else { $c = "NA"; push @array, $c; } print Dumper @array;

    Pre-posting afterthought: it's not entirely clear whether you want an array for each row or a single, comprehensive array (or "corresponding list" as you expressed it in the narrative) so you may have to extrapolate from the code above to achieve your goal... if, indeed, you see any advantage here.

    Small point: Though I myself tend to be generous with whitespace, the blank lines in your code mostly make it harder to read (here, anyway).

      push @array, map { $_ //= 'NA'; $_ } $a, $b, $c, $d, $e, $f, $g;
      perl -E'sub Monkey::do{say$_,for@_,do{($monkey=[caller(0)]->[3])=~s{::}{ }and$monkey}}"Monkey say"->Monkey::do'
Re: Short version of database push for multiple variables
by Eliya (Vicar) on May 13, 2012 at 16:04 UTC

    Maybe something like this (if I understand your "append them to corresponding list" correctly):

    #!/usr/bin/perl -w use strict; my (@a, @b, @c, @d, @e, @f, @g); while (my $Line = <DATA>) { my @v = split(/\t/, $Line); for my $ar ( \(@a, @b, @c, @d, @e, @f, @g) ) { my $v = shift @v; $v = "NA" unless $v =~ /([A-Za-z0-9-_]+)/; push @$ar, $v; } } use Data::Dumper; print Dumper \(@a, @b, @c, @d, @e, @f, @g); __DATA__ a b c d . f g A B C . E F G

    Output:

    $VAR1 = [ 'a', 'A' ]; $VAR2 = [ 'b', 'B' ]; $VAR3 = [ 'c', 'C' ]; $VAR4 = [ 'd', 'NA' ]; $VAR5 = [ 'NA', 'E' ]; $VAR6 = [ 'f', 'F' ]; $VAR7 = [ 'g ', 'G ' ];
Re: Short version of database push for multiple variables
by BrowserUk (Pope) on May 13, 2012 at 16:06 UTC

    Kinda depends what mean by "blank"?

    If the file contains two successive tabs with nothing in between, the result of split will undef, and you can use defined-or:

    my @a = map $_//'NA', split /\t/, $line;

    If there might be spaces, or empty quotes between the tabs, you need to use else.


    With the rise and rise of 'Social' network sites: 'Computers are making people easier to use everyday'
    Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
    "Science is about questioning the status quo. Questioning authority".
    In the absence of evidence, opinion is indistinguishable from prejudice.

    The start of some sanity?

      This seems perfect. I can just replace anything blank in a line with 'NA' and then append elements of (in your example) @a to appropriate lists. Thanks for that.

      A problem though. I presume it was supposed to be //'NA'/. The blanks are two succesive tabs but I get a illegal division by zero with this command. Any idea why?
        I presume it was supposed to be //'NA'/.

        No. What I posted was tested, working code. The defined-or operator is: //. Ie. The full line with a couple of extra spaces is:

        my @a = map $_ // 'NA', split /\t/, $line;

        The extra / you are adding is the cause of your divide by zero message.


        With the rise and rise of 'Social' network sites: 'Computers are making people easier to use everyday'
        Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
        "Science is about questioning the status quo. Questioning authority".
        In the absence of evidence, opinion is indistinguishable from prejudice.

        The start of some sanity?

        In case the original version doesn't work for you (error "Search pattern not terminated at ..."), your Perl might be too old (<5.10).  In this case, you could say instead

        my @a = map defined $_ ? $_ : 'NA', split /\t/, $line;

        Or upgrade Perl.

        BTW, AFAICT, split /\t/ on two consecutive tabs wouldn't return undef, but rather '' (the empty string):

        $ perl -MData::Dumper -e'@a = split /\t/, "foo\t\tbar"; print Dumper \ +@a' $VAR1 = [ 'foo', '', 'bar' ];

        So the whole "//" thing is moot anyway.  It wouldn't even work:

        $ perl -MData::Dumper -e'@a = map $_//"NA", split /\t/, "foo\t\tbar"; +print Dumper \@a' $VAR1 = [ 'foo', '', 'bar' ];

        In other words, you probably want:

        $ perl -MData::Dumper -e'@a = map $_ ne "" ? $_ : "NA", split /\t/, "f +oo\t\tbar"; print Dumper \@a' $VAR1 = [ 'foo', 'NA', 'bar' ];
Re: Short version of database push for multiple variables
by jwkrahn (Monsignor) on May 13, 2012 at 20:22 UTC
    my @fields = map length ? $_ : 'NA', split /\t/, $Line, -1;

Log In?
Username:
Password:

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://970291]
Approved by ww
help
Chatterbox?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others drinking their drinks and smoking their pipes about the Monastery: (5)
As of 2014-12-25 07:55 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    Is guessing a good strategy for surviving in the IT business?





    Results (159 votes), past polls