tags:

views:

322

answers:

6

I smell something bad here?

    if ($col == 24) {
        $buffer{'Y'} = trim($val);
        return;
    }

    if ($col == 25) {
        $buffer{'Z'} = trim($val);
        return;
    }

    if ($col == 26) {
        $buffer{'AA'} = trim($val);
        return;
    }

    if ($col == 27) {
        $buffer{'AB'} = trim($val);
        return;
    }
A: 

In other programming languages, you'd use a switch statement. This page has several ways to emulate a switch statement in Perl (5+).

Of course, if I had bothered to read the question closely, I wouldn't have suggested a switch statement for handling a specific sequence of inputs to outputs.

Mark Rushakoff
perl 5.10.x has default switch (use Switch.pm for older version). But switch statement, imho, is just same ugly as repeated if - only looks cleaner.
est
There's no need for a switch statement here, since every option does the same basic thing. As George Phillips demonstrated, a hash works fine.
friedo
+2  A: 

Find a way to encode "$col" into a string that represents that column in the hash (i.e. turns 25 into 'Z' and 26 into 'AA' etc).

sub encodeCol {
  ...
}

$buffer{encodeCol($col)} = trim($val);
dreamlax
+1 for being faster than me
willoller
+12  A: 

Associative arrays work well in these cases. First initialize:

my %colToBuffer = ( 24 => 'Y', 25 => 'Z', 26 => 'AA', 27 => 'AB');

Then the code can be:

if (exists $colToBuffer{$col})
{
    $buffer{$colToBuffer{$col}} = trim($val);
}

Season to taste.

George Phillips
+1, very concise! Although, probably not too good if you have to initialise a lot of values.
dreamlax
I typed up the equivalent, but in Python since I don't know Perl. I'll just +1 you instead.
FogleBird
A: 

In C-like pseudocode, to encode the column numbers:

alphabet[1:26] = {'A','B','C','D',...,'Z'}
col = col + 1; // so that 1=A, ..., 26=Z
string = "";

while(col > 0) {
    letterRank = col % 26; // % for modulo
    string = concatenate(alphabet[letterRank], string);
    col = col / 26; // integer division
}
Matt Nizol
+14  A: 

The names look suspicious, too. If you're looping through the columns, try the magic ++ operator.

my $colname = 'A';
for (0..$#cols)
{
   # do stuff with $colname
   $buffer{$colname} = trim($val);
   ++$colname;
}

If not, there does seem to be a pattern here that you can exploit for converting numbers from decimal (digital) to alphabetic. You'd do it the same way you'd convert a digital number to decimal, except that you'd use characters A-Z, base 26, instead of 0-9, base 10. Something like:

sub colname
{
  my $num = shift;
  my $name = '';
  while ($num)
  {
    $name .= chr(ord('A') + $num % 26);
    $num /= 26;
  }
  reverse $name;
}

(untested) This algorithm is language-neutral. It doesn't particularly take advantage of perlishness, but works wonderfully as a general-case.

Update: I told you this was untested. j_random_hacker pointed out the thinko, and I've corrected it. Thanks!

Tanktalus
precisely what I need - thank!
est
Shouldn't that last line read "reverse $name;"? Otherwise good.
j_random_hacker
-1ing to get your attention... ;)
j_random_hacker
Fixed, so +2 for you :)
j_random_hacker
+1  A: 

If $col is in 24..27, then calculate the corresponding letter, and set the proper hash entry. Here are two ways to do it, depending on whether you want to save a few characters or save a few bytes:

24 <= $col && $col <= 27 and $buffer{('A'..'AB')[$col]} = trim($val);

or

24 <= $col && $col <= 27 and $buffer{('Y'..'AB')[$col - 24]} = trim($val);