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

Hi Everyone,

I would like to get suggestions on how to efficiently write a program. I explain below what the program does.

I have an array with values say 1 to 70. And I have a list which has values 1,10,20,40,60. Basically I need to output the array into different files where the first file will have values from 1 to 9, second from 10 to 19, third from 20 to 39, fourth from 40 to 59 and fifth from 60 to end.

I am assuming the best way to write this is to go through the array only once and not multiple times. But, I need to open 5 files simultaneously and first write a 1 line header into all of them and then start printing out the elements of the array.

Please let me know your suggestions on how to do this right or if the problem is not clear.

Thanks,

Jagan

Here's what I have written. Works perfectly and gives me what I need but I want to know if it is the best way to write it or can I write it better. Please let me know if you don't understand things in the code. The foreach loop goes through the array, opens a new file, write the 1 line header, then checks if the element needs to be written to the file and if not then closes the current file and a new file is opened in the next iteration.
#!/usr/bin/perl -w use strict; use warnings; my $num_args=$#ARGV+1; if($num_args<2) { print "Usage: doc_create.pl <particle folder> <particle list>" +; exit; } chomp(my $part_folder=$ARGV[0]); chomp(my $part_list=$ARGV[1]); open PLIST,"<$part_list" || die "Can't open file: $!"; my @part_id=<PLIST>; close PLIST; foreach (@part_id) { chomp($_); } #print "@part_id"; my $part_id=join(" ",@part_id); print "$part_id\n"; my @part_list=split(" ",$part_id); #foreach (@part_list) { # print "$_\n"; #} my $pattern=$part_folder."_???.spi"; my $particles=`ls $part_folder/$pattern`; #print "$particles\n"; my @particles=split(/\n/,$particles); my $doublet=1; my $i=0; open OFDOC,">images.doc" || die "Can't open file: $!"; open OFSEL,">images.sel" || die "Can't open file: $!"; print OFDOC " ; Headerinfo columns: rot (1), tilt (2), psi (3), Xoff ( +4), Yoff (5), Zoff (6), Ref (7), Wedge (8), Pmax/sumP (9), LL (10)\n" +; foreach (@particles) { chomp($_); my $part_id=substr($_,-7,-4); #print "$part_id\n"; if ($i==0) { open ODOC,">images_$doublet.doc" || die "Can't open fi +le: $!"; open OSEL,">images_$doublet.sel" || die "Can't open fi +le: $!"; print ODOC " ; Headerinfo columns: rot (1), tilt (2), +psi (3), Xoff (4), Yoff (5), Zoff (6), Ref (7), Wedge (8), Pmax/sumP +(9), LL (10)\n"; $i++; goto CHECK; } else { open ODOC,">>images_$doublet.doc" || die "Can't open f +ile: $!"; open OSEL,">>images_$doublet.sel" || die "Can't open f +ile: $!"; CHECK: my $x=2*$doublet-1; my $y=2*$doublet+1; if ($doublet<9) { my $start_id=$part_list[$x]; my $end_id=$part_list[$y]; if ($part_id>=$start_id && $part_id<$end_id) { print OSEL "../$_ $doublet\n"; print ODOC " ; ../$_\n"; printf ODOC " %3d 10 0.00000 0. +00000 0.00000 0.00000 0.00000 0.00000 %.5f 1.00000 + 0.00000 0.00000\n",$part_id,$doublet; print OFSEL "../$_ $doublet\n"; print OFDOC " ; ../$_\n"; printf OFDOC " %3d 10 0.00000 0 +.00000 0.00000 0.00000 0.00000 0.00000 %.5f 1.00000 + 0.00000 0.00000\n",$part_id,$doublet; } else { $doublet++; $i=0; close ODOC; close OSEL; } } else { my $start_id=$part_list[$x]; if ($part_id>=$start_id) { print OSEL "../$_ $doublet\n"; print ODOC " ; ../$_\n"; printf ODOC " %3d 10 0.00000 0. +00000 0.00000 0.00000 0.00000 0.00000 %.5f 1.00000 + 0.00000 0.00000\n",$part_id,$doublet; print OFSEL "../$_ $doublet\n"; print OFDOC " ; ../$_\n"; printf OFDOC " %3d 10 0.00000 0 +.00000 0.00000 0.00000 0.00000 0.00000 %.5f 1.00000 + 0.00000 0.00000\n",$part_id,$doublet; } else { $doublet++; $i=0; close ODOC; close OSEL; } } } } close OFDOC; close OFSEL;

Replies are listed 'Best First'.
Re: Suggestion on a Program
by choroba (Cardinal) on Dec 02, 2015 at 16:34 UTC
    You don't need to open several files at the same time. Just open a new file only when you need to.
    #!/usr/bin/perl use warnings; use strict; my @values = 1 .. 70; my @boundaries = (1, 10, 20, 40, 60); my $OUT; my $index = 0; for my $value (@values) { if ($index <= $#boundaries && $value == $boundaries[$index]) { $index++; open $OUT, '>', "output.$index" or die $!; print {$OUT} "HEADER\n"; } print {$OUT} $value, "\n"; }
    ($q=q:Sq=~/;[c](.)(.)/;chr(-||-|5+lengthSq)`"S|oS2"`map{chr |+ord }map{substrSq`S_+|`|}3E|-|`7**2-3:)=~y+S|`+$1,++print+eval$q,q,a,
      Thanks for the reply. I figured that and in my code that I already pasted I have opened files one at a time and closed it when done.
Re: Suggestion on a Program
by 1nickt (Canon) on Dec 02, 2015 at 16:32 UTC
    Hi, you are much more likely to get a helpful answer if you post what you've tried so far.
    The way forward always starts with a minimal test.
Re: Suggestion on a Program
by AnomalousMonk (Archbishop) on Dec 02, 2015 at 21:14 UTC

    A generalized approach to partitioning a list into sub-lists prior to processing the sub-lists (e.g., by writing each to an individual file):

    c:\@Work\Perl\monks>perl -wMstrict -le "use List::MoreUtils qw(part first_value); ;; use Data::Dump qw(dd); ;; my @data = (-10 .. 50, 60 .. 70, reverse 51 .. 59); dd \@data; ;; my @ranges = (1, 10, 18, 19, 41, 60); ;; my @parts = part { range_of($_, \@ranges) } @data; dd \@parts; ;; write_partition_to_file(@$_) for @parts[ 1 .. $#parts ]; ;; sub range_of { my ($n, $ar_ranges) = @_; ;; my $r = first_value { $ar_ranges->[$_-1] <= $n && $n < $ar_ranges->[$_]; +} 1 .. $#$ar_ranges ; return defined($r) ? $r : $n < $ar_ranges->[0] ? 0 : $n >= $ar_ranges->[-1] ? @$ar_ranges : die qq{range_of($n) failed} ; } ;; sub write_partition_to_file { print qq{@_}; } " [-10 .. 50, 60 .. 70, 59, 58, 57, 56, 55, 54, 53, 52, 51] [ [-10 .. 0], [1 .. 9], [10 .. 17], [18], [19 .. 40], [41 .. 50, 59, 58, 57, 56, 55, 54, 53, 52, 51], [60 .. 70], ] 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 59 58 57 56 55 54 53 52 51 60 61 62 63 64 65 66 67 68 69 70


    Give a man a fish:  <%-{-{-{-<