nimdokk has asked for the wisdom of the Perl Monks concerning the following question:

I'm working on a report to be run with Perl that creates a comma-separated text file. Initially I had it set to parse out an array and fill in values at certain slices based on what it is. At first, if the particular value was not present, it would create an empty field. No problem at all with this, but in thinking about it, I decided to have the array "auto-filled" with 'N/A' so that instead of a blank, we would have 'N/A' if there was no value for the particular field. What I have below does the trick quite nicely, but I'm wondering if there might not be a better way to accomplish this:

my @list=split (/,/, 'N/A,' x 14);

This is simply what I came up with off the top of my head in about 30 seconds. Are there other ways of accomplishing this? Something that might avoid doing the split.

Replies are listed 'Best First'.
Re: Auto-filling an array
by Limbic~Region (Chancellor) on Mar 28, 2005 at 18:29 UTC
      Thanks, that ought to do the trick quite nicely. I'm sure there's a much nicer way to do all of this, but I've got it working, don't want to mess around with it too much (unless I find myself bored at some point :-)
        nimdokk,
        See Multiplicative Operators in perldoc perlop for more details. Having code that works is important, but you might want to check out Value of "RE"-coding for the newbie to see why there can be value in messing around as you put it.

        Cheers - L~R

Re: Auto-filling an array
by moot (Chaplain) on Mar 28, 2005 at 18:28 UTC
    Sounds like you want something like
    # To replace any empty value (including undefined): my @list = map { $_ || 'N/A' } @fields; # or, to replace only undefined values, leaving empty ones as empty st +rings: my @list = map { defined $_ ? $_ : 'N/A' } @fields;
    Season @fields to taste (for example, @fields might be the result of another map, or a split).
Re: Auto-filling an array
by ikegami (Patriarch) on Mar 28, 2005 at 18:48 UTC

    And then there's

    my @list; push(@list, 'N/A') for (1..14);

    Perl's push, pop, shift and unshift are extremely efficient. They don't copy the entire array, unlike @list=('N/A')x14. In addition, for (a..b) is also very efficient. It is optimised to not create a list, unlike ('N/A')x14.

    That said, I like the idea of leaving the array undefined, and replacing each undef with "N/A" when printing.

      I was very intrigued by ikegami's post, so I went ahead and benchmarked the two approaches:

      use Benchmark 'cmpthese'; cmpthese( -1, { x => sub { my @list = ( 'N/A' ) x 14 }, push => sub { my @list; push @list, $_ for 1 .. 14 } } ); Rate times push x 89321/s -- -23% push 115925/s 30% --
      Where would I be without Benchmark?

      the lowliest monk

      I actually tried putting the 'N/A's in when I was writing the list, but the data was not coming back right, so I went with a more brute force approach. That said of course. I'm going to be looking at other ways to tighten this script up.
Re: Auto-filling an array
by legato (Monk) on Mar 28, 2005 at 18:38 UTC
    My approach has been to do some quick post-processing. For example, this chunk from a processor that uses Text::CSV_XS for reading and splitting each line: null values are usually undef, and I change them to the string '<NULL>' that an up-stream processor requires.
    $line = $csv->getline($io); # .. some error-handling stuff. for (@$line) { $_ = '<NULL>' unless defined } #~ @$line = map { defined $_ ? $_ : '<NULL>' } @$line
    Note that commented-out line: that works just as well. I haven't benchmarked it, so I don't know which is faster, but other maintainers were griping about the map{}, so I replaced it.

    The basic logic (in both cases) is that I look for undefined values (you could also look for the empty string by substituting $_ eq '' for defined $_) and replace them with something.

    This is, in general, better than prefilling: you need not alter this code if the length of your lines change.

    Anima Legato
    .oO all things connect through the motion of the mind