For Programmers: Free Programming Magazines  


Home > Archive > PERL Programming > October 2005 > Better code









You are viewing an archived Text-only version of the thread. To view this thread in it's original format and/or if you want to reply to this thread please [click here]

 

Author Better code
George Bouras

2005-10-05, 6:56 pm

The following work just fine, but I did not like the duplicated lines.

open(FILE1, "<$file1");
open(FILE2, "<$file2");
while(<FILE1> ) { chomp; next if /^\s*$/; s/\s*(.*)\s*/\1/; @list1{ split(
/\s*,\s*/ ,$_) } = 1 }
while(<FILE2> ) { chomp; next if /^\s*$/; s/\s*(.*)\s*/\1/; @list2{ split(
/\s*,\s*/ ,$_) } = 1 }
close FILE1;
close FILE2;
map { $list1_nocase{ lc $_ } = 1 } keys %list1;
map { $list2_nocase{ lc $_ } = 1 } keys %list2;


So I used a for. At the loop you can handle the values but
not the names of the data holders like arrays, variables,
hashes ... so I used the eval statements. The loop code also
works ok but again I do not like the eval statements because they
are slow and ugly. The question is how to make the initial
code unique without the "eval" ? with glob references maybe ?
If the similar pieces was 100 the problem would be bigger.


for my $i (1,2)
{
my $file = eval "\$file$i";
local *FILE = \"FILE$i";
open(FILE, "<$file");
while(<FILE> ) { chomp; next if /^\s*$/; s/\s*(.*)\s*/\1/; eval "\@list$i\{
split( /\\s*,\\s*/ ,\$_ ) \} = 1" }
close FILE;
eval "map { \$list$i_nocase{ lc \$_ } = 1 } keys \%list$1";
$}



Paul Lalli

2005-10-05, 6:56 pm

George Bouras wrote:
> The following work just fine, but I did not like the duplicated lines.
>
> open(FILE1, "<$file1");
> open(FILE2, "<$file2");
> while(<FILE1> ) { chomp; next if /^\s*$/; s/\s*(.*)\s*/\1/; @list1{ split(
> /\s*,\s*/ ,$_) } = 1 }
> while(<FILE2> ) { chomp; next if /^\s*$/; s/\s*(.*)\s*/\1/; @list2{ split(
> /\s*,\s*/ ,$_) } = 1 }
> close FILE1;
> close FILE2;
> map { $list1_nocase{ lc $_ } = 1 } keys %list1;
> map { $list2_nocase{ lc $_ } = 1 } keys %list2;
>
>
> So I used a for. At the loop you can handle the values but
> not the names of the data holders like arrays, variables,
> hashes ... so I used the eval statements. The loop code also
> works ok but again I do not like the eval statements because they
> are slow and ugly. The question is how to make the initial
> code unique without the "eval" ? with glob references maybe ?
> If the similar pieces was 100 the problem would be bigger.
>
>
> for my $i (1,2)
> {
> my $file = eval "\$file$i";
> local *FILE = \"FILE$i";
> open(FILE, "<$file");
> while(<FILE> ) { chomp; next if /^\s*$/; s/\s*(.*)\s*/\1/; eval "\@list$i\{
> split( /\\s*,\\s*/ ,\$_ ) \} = 1" }
> close FILE;
> eval "map { \$list$i_nocase{ lc \$_ } = 1 } keys \%list$1";
> $}


Why not just make subroutines? And why not use lexical filehandle
references instead of messing with global typeglobs? And why not use
real hashes and arrays rather than messing with evals and symrefs?

[UNTESTED]
#!/usr/bin/perl
use strict;
use warnings;
use Data::Dumper;

sub read_file {
my $filename = shift;
my %list;
open my $fh, '<', $filename or die "Cannot open $filename: $!\n";
while (<$fh> ){
chomp;
next if /^\s*$/;
s/^\s+//;
s/\s+$//; #more efficient than the combined statement
@list{split /\s*,\s*/, $_} = 1;
}
return \%list;
}

my (@lists, @lists_no_case);
foreach my $file ('FILE1', 'FILE2'){
my $list_ref = read_file($file);
my %list_no_case = map { lc $_ => 1 } keys %list_ref;
push @lists, $list_ref;
push @lists_no_case, \%list_no_case;
}

print Dumper(\@lists, \@lists_no_case);

__END__

Paul Lalli

John W. Krahn

2005-10-05, 6:56 pm

George Bouras wrote:
> The following work just fine, but I did not like the duplicated lines.
>
> open(FILE1, "<$file1");
> open(FILE2, "<$file2");
> while(<FILE1> ) { chomp; next if /^\s*$/; s/\s*(.*)\s*/\1/; @list1{ split(
> /\s*,\s*/ ,$_) } = 1 }
> while(<FILE2> ) { chomp; next if /^\s*$/; s/\s*(.*)\s*/\1/; @list2{ split(
> /\s*,\s*/ ,$_) } = 1 }
> close FILE1;
> close FILE2;
> map { $list1_nocase{ lc $_ } = 1 } keys %list1;
> map { $list2_nocase{ lc $_ } = 1 } keys %list2;
>
>
> So I used a for. At the loop you can handle the values but
> not the names of the data holders like arrays, variables,
> hashes ... so I used the eval statements. The loop code also
> works ok but again I do not like the eval statements because they
> are slow and ugly. The question is how to make the initial
> code unique without the "eval" ?


local @ARGV = ( $file1, $file2 );
my $key = 'list1';
my %data;
while ( <> ) {
$key = 'list2' if eof;
next unless /\S/;
my @fields = map { s/\A\s+//; s/\s+\z//; $_ } split /,/;
@{ $data{ $key } }{ @fields } = ();
@{ $data{ "${key}_nocase" } }{ map lc, @fields } = ();
}



John
--
use Perl;
program
fulfillment
Sponsored Links







Also available: Server administration forum archive | Web Design forum archive | Software forum archive | Hardware reviews archive

Copyright 2008 codecomments.com