I want to write my hash map data into Excel [closed] - perl

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 5 years ago.
Improve this question
Below is the output I got when I use print Dumper(\%Data) in my code
{
"" => undef,
"123456789012:SRIRAMA" => [123456789012, "SRIRAMA", 856.06, 0, 0, 0],
"389252737122:RAMA" => [389252737122, "RAMA", 345.76, 0, 0, 0],
}
This data I have to write to an Excel file like below
Number Name number name amt amt2 amt3 amt4
123456789012 SRIRAMA 123456789012 SRIRAMA 856.06 0 0 0
389252737122 RAMA 389252737122 RAMA 345.76 0 0 0
The first two columns are one SQL result and rest of the columns are another SQL query result.
The first query result I have put in a map and searched based on the key in second query result and finally I got the output above.
Here, Number and Name—the first two columns—are keys for searching the data.
The code below is after getting the SQL result:
foreach ( #Sqlresult ) {
$rec_cntr = $rec_cntr + 1;
my #fields = undef;
chop;
next if /^$/;
next if /ERROR:/;
next if /ORA-/;
#fields = split( /::/, $_ );
my $fldref = #fields;
$ent_id = undef;
$ent_id = $fields[0];
$key = undef;
$key = $fields[0] . ":" . $name;
push( #{ $Data{$key} }, $fields[1] );
}
$rec_cntr = 0;
The below code snippet I use when the records are not there pushing as zero.
my $kkey = undef;
for $kkey ( sort keys %Data ) {
next if $kkey eq '';
my $Lent = #{ $Data{$kkey} };
if ( $Lent < 5 ) {
push( #{ $Data{$kkey} }, 0 );
}
print scalar #{ $Data{$kkey} };
}
print Dumper( \%Data );
The above print Dumper produces the information shown at the start of the question
Here is where the data is written into an Excel sheet
my $dt = `date +%m-%d-%Y_%\I%\M`;
chop $dt;
my $FileName = "/data_reports/AdjestedFile" . $dt . ".xls";
#my $workbook = Spreadsheet::WriteExcel->new( $FileName );
my $workbook = Excel::Writer::XLSX->new( $FileName );
# Define the format and add it to the worksheet
my $format = $workbook->add_format(
center_across => 1,
bold => 1,
size => 10,
color => "black",
bg_color => "grey",
border_color => "black",
align => "vcenter",
);
my $formatnum = $workbook->add_format();
$formatnum->set_num_format( '00000000000' );
my $formatamt = $workbook->add_format();
$formatamt->set_num_format( '0.00' );
$formatamt->set_align( 'right' );
my $formattext = $workbook->add_format( num_format => '#' );
my $prev_feetype = "";
my $current_ws;
$current_ws = $workbook->add_worksheet();
$current_ws->keep_leading_zeros( 1 );
$current_ws->set_column( 0, 16, 17, $formattext );
$current_ws->set_column( 1, 1, 13, $formattext );
$current_ws->set_column( 2, 2, 10, $formatnum );
$current_ws->set_column( 3, 3, 10, $formattext );
$current_ws->set_column( 4, 4, 10, $formattext );
$current_ws->set_column( 5, 5, 10, $formattext );
$current_ws->set_column( 6, 6, 10, $formattext );
$current_ws->set_column( 7, 7, 10, $formattext );
my $cl = 0;
$current_ws->write_string( 0, $cl++, "Number", $format );
$current_ws->write_string( 0, $cl++, "Name", $format );
$current_ws->write_string( 0, $cl++, "amt", $format );
$current_ws->write_string( 0, $cl++, "NA", $format );
$current_ws->write_string( 0, $cl++, "NA", $format );
$current_ws->write_string( 0, $cl++, "NA", $format );
$current_ws->write_string( 0, $cl++, "NA", $format );
$current_ws->write_string( 0, $cl++, "NA", $format );
my $rownum = 1;
foreach ( %Data ) {
my #fields = undef;
chop;
next if /^$/;
#fields = split( /,/, $_ );
my $fldref = \#fields;
my $clcntr = 0;
my $ent_id = "";
foreach ( #fields ) {
if ( $clcntr == 1 ) {
$ent_id = $_;
}
if ( isfloat( $_ ) ) { #and $clcntr != 9 ) {
$current_ws->write_number( $rownum, $clcntr++, $_ );
}
else {
$current_ws->write_string( $rownum, $clcntr++, $_ );
}
}
}

There's a lot to read there, but these ideas may help
Always use strict and use warnings at the top of every Perl program you write. It is invaluable for locating the more obvious bugs
Don't initialise arrays with #data = undef. If you want to empty an existing array then write #data = (). If you are declaring a new array then my #data will create a new empty array
The exact same advice applies to hashes, and that will be the reason for the "" => undef at the start of your %Data hash
Don't use my $dt = `date +%m-%d-%Y_%\I%\M`. You are starting a whole new shell process just to ask it the time. You should
use Time::Piece;
and
my $dt = localtime->strftime('%m-%d-%Y_%I%M');
The result from this won't need chomping
But are you sure you want %I? That gives you the 12-hour time, so the value will reset to zero at midday. %H gives you 24-hour time, and is much more likely to be useful
chomp is preferable to chop unless you're doing something unusual. chop will just remove the last character from a string, whatever it is, while chomp will remove the last character if it is a newline
for ( %Data ) { ... } will loop over the hash setting $_ to key1, val1, key2, val2 etc. That isn't what you want
In this case, since the information in the key is duplicated in the value, you probably want for ( values %Data ) { ... }. But that value is an array reference so no splitting is required
This is probably closer to what you need
my $rownum = 0;
for my $values ( values %Data ) {
my $colnum = 0;
for my $val ( #$values ) {
if ( isfloat($_) ) {
$current_ws->write_number( $rownum, $colnum++, $val );
}
else {
$current_ws->write_string( $rownum, $colnum++, $val );
}
}
}

Related

How to delete entire column in Excel sheet and write updated data in new excel file using Perl?

I am new to Perl. I have excel file say "sample.xls" which looks like follows.
Sample.xls
There are about data of 1000 rows like this. I want to parse this file and write it in another file say "output.xls" with following output format.
output.xls
I have written a script in perl, however, it doesn't give me the exact output the way I want. Also, looks like the script is not very efficient. Can anyone guide me how I can improve my script as well as have my output as shown in "output.xls" ??
Here's the Script:
#!/usr/bin/perl –w
use strict;
use warnings;
use Spreadsheet::ParseExcel;
use Spreadsheet::WriteExcel;
use Spreadsheet::WriteExcel::Chart;
# Read the input and output filenames.
my $inputfile = "path/sample.xls";
my $outputfile = "path/output.xls";
if ( !$inputfile || !$outputfile ) {
die( "Couldn't find file\n" );
}
my $parser = Spreadsheet::ParseExcel->new();
my $inwb = $parser->parse( $inputfile );
if ( !defined $inwb ) {
die "Parsing error: ", $parser->error(), ".\n";
}
my $outwb = Spreadsheet::WriteExcel->new( $outputfile );
my $inws = $inwb->worksheet( "Sheet1" );
my $outws = $outwb->add_worksheet("Sheet1");
my $out_row = 0;
my ( $row_min, $row_max ) = $inws->row_range();
my ( $col_min, $col_max ) = $inws->col_range();
my $format = $outwb->add_format(
center_across => 1,
bold => 1,
size => 10,
border => 4,
color => 'black',
border_color => 'black',
align => 'vcenter',
);
$outws->write(0,0, "Item Name", $format);
$outws->write(0,1, "Spec", $format);
$outws->write(0,2, "First name", $format);
$outws->write(0,3, "Middle Name", $format);
$outws->write(0,4, "Last Name", $format);
$outws->write(0,5, "Customer Number", $format);
$outws->write(0,6, "Age", $format);
$outws->write(0,7, "Units", $format);
my $col_count = 1;
#$row_min = 1;
for my $inws ( $inwb->worksheets() ) {
my ( $row_min, $row_max ) = $inws->row_range();
my ( $col_min, $col_max ) = $inws->col_range();
for my $in_row ( 2 .. $row_max ) {
for my $col ( 0 .. 0 ) {
my $cell = $inws->get_cell( $in_row, $col);
my #fields = split /_/, $cell->value();
next unless $cell;
$outws->write($in_row,$col, $cell->value());
$outws->write($in_row,$col+1, $fields[1]);
}
}
for my $in_row ( 2 .. $row_max ) {
for my $col ( 1 .. 1 ) {
my $cell = $inws->get_cell( $in_row, $col);
my #fields = split /_/, $cell->value();
next unless $cell;
#$outws->write($in_row,$col+1, $cell->value());
$outws->write($in_row,$col+1, $fields[0]);
$outws->write($in_row,$col+2, $fields[1]);
$outws->write($in_row,$col+3, $fields[2]);
$outws->write($in_row,$col+4, $fields[3]);
}
}
for my $in_row ( 2 .. $row_max ) {
for my $col ( 2 .. 2 ) {
my $cell = $inws->get_cell( $in_row, $col);
my #fields = split /_/, $cell->value();
next unless $cell;
$outws->write($in_row,6, $cell->value());
}
}
for my $in_row ( 2 .. $row_max ) {
for my $col ( 3 .. 9 ) {
my $cell = $inws->get_cell( $in_row, $col);
next unless $cell;
}
}
for my $in_row ( 2 .. $row_max ) {
for my $col ( 10 .. 10 ) {
my $cell = $inws->get_cell( $in_row, $col );
next unless $cell;
$outws->write($in_row,7, $cell->value());
}
}
}
To get your output sorted, you need to collect all the information first before you are writing it out. Right now, you are doing a bit of jumping back and forth between rows and columns.
Here are some changes I would make to get it sorted, and make it more efficient (to read).
Create a data structure $data outside of your loop to store all the information.
If there is only one worksheet, you don't need to loop over sheets. Just work with one sheet.
Loop over the lines.
Inside that loop, use the code you have to parse the individual fields to just parse them. No 2..2 loops. Just a bunch of statements.
my #item_fields = split /_/, $inws->get_cell( $in_row, 0 ) || q{};
my #name_fields = split /_/, $inws->get_cell( $in_row, $col ) || q{};
Store them in $data per item.
push #{ $data } = [ $item_fields[0], ... ];
Done with the loop. Open the output file.
Loop over $data with a sort and write to the output file.
foreach my $row (sort { $a->[0] cmp $b->[0] } #{ $data } ) { ... }
Done.
I suggest you read up on sort and also check out perlref and perlreftut to learn more about references (data structures).

perl: sprintf for element in list

I've been really confused about this, I'm trying to create a big matrix of numbers and I want to use sprintf with perl to have a nicer output. I'm trying to use sprintf like so
my $x = 0;
my $y = 0;
for ($x=1; $x<=$steps; $y++) { # loop through lines
for ($y=0; $y<=$distances; $y++) {
my $format = sprintf ("%s",$matrix[$x][$y]);
but this is really doing my head in, as I am looping through all the values of $x and $y and getting their combinations. So I am not sure if I'm meant to use more formatting arguments like so
my $format = sprintf ("%s%s%s",$matrix[$x][$y]);
(of course this is giving me compilation errors as it's not right)
But when I only use one argument, I can't put spaces in between my columns :/ Can somebody explain what's happening? I really don't understand what I'm meant to do to get the formatting nice. I'm looking to just align the columns and have a couple of whitespaces between them. Thank you all so much.
I would be thinking in terms of using map, as a way to display every element:
#!/usr/bin/env perl
use strict;
use warnings;
my #matrix = ( [1,2,3,4],
[5,6,7,8],
[9,10,11,12], );
print join ("\n", map { join ( "\t", #$_ ) } #matrix );
This is formatting on tab-stops, rather than fixed width columns, and outputs:
1 2 3 4
5 6 7 8
9 10 11 12
If you particularly wanted sprintf though:
foreach my $row ( #matrix ) {
print map { sprintf("%5s", $_) } #$row,"\n";
}
(5 columns wide).
In each of these, I'm working on whole rows - that only really applies though, if I'm right about the assumptions I've made about which elements you're displaying.
At a very basic level - your code could work as:
#!/usr/bin/env perl
use strict;
use warnings;
my #matrix = ( [ 1, 2, 3, 4 ],
[ 5, 6, 7, 8 ],
[ 9, 10, 11, 12 ], );
my $steps = 2;
my $distances = 3;
for ( my $x = 1; $x <= $steps; $x++ ) { # loop through lines
for ( my $y = 0; $y <= $distances; $y++ ) {
printf( "%5s", $matrix[$x][$y] );
}
print "\n";
}
Although note - that will only work with equal numbers of columns. You could, however, do something like:
#!/usr/bin/env perl
use strict;
use warnings;
my #matrix = ( [ 1, 2, ],
[ 3, 4, 5, ],
[ 6, 7, 8, 9, 10, 11, 12 ], );
my $steps = 2;
my $distances = 3;
for ( my $x = 1; $x <= $steps; $x++ ) { # loop through lines
for ( my $y = 0; $y <= $distances; $y++ ) {
printf( "%5s", $matrix[$x][$y] // '' );
}
print "\n";
}
Which omits the first row (because you set $x to 1), and iterates up to 4 columns:
3 4 5
6 7 8 9
This omits the extra values on the last line, and uses // to test if the cell is empty or not.
for my $row (#matrix) {
my $format = join(' ', ('%5.2f') x #$row)."\n";
printf($format, #$row);
}
If all rows have the same number of columns, you could calculate the format once.
if (#matrix) {
my $format = join(' ', ('%5.2f') x #{$matrix[0]})."\n";
for my $row (#matrix) {
printf($format, #$row);
}
}
If the size of the columns isn't unknown in advance, you'll need to need to perform the following in order:
Format the cells (if needed),
Find the length of the largest cell of each column, then
Print out the matrix with padding.
The following assumes every row of the matrix is the same length.
use List::Util qw( max );
if (#matrix) {
for my $row (#matrix) {
$_ = sprinf('%.2f', $_) for #$row;
}
my $num_cols = #{$matrix[0]};
my #col_sizes = (0) x $num_cols;
for my $row (#matrix) {
$col_sizes[$x] = max(0, $col_sizes[$x], $row->[$x]);
}
my $format = join(' ', map { "%$_s" } #col_sizes)."\n";
for my $row (#matrix) {
printf($format, #$row);
}
}

List array find double and add value

the original perl array is sorted and looks like this:
Original ARRARY:
ccc-->2
ccc-->5
abc-->3
abc-->7
cb-->6
and i like to have the following result:
FINAL ARRARY:
ccc-->7
abc-->10
cb-->6
Question:
can you please create a subroutine for that ?
this was the orig. subroutine that i used:
sub read_final_dev_file {
$dfcnt=0;
$DEVICE_ANZSUMZW=0;
$DEVICE_ANZSUM=0;
open(DATA,"$log_dir1/ALLDEVSORT.$log_file_ext1") || die ("Cannot Open Logfile: $log_dir1/$log_DEV_name.$log_file_ext1 !!!!");
#lines = <DATA>;
close(DATA);
chomp(#lines); # erase the last sign from a string
foreach $logline (#lines) {
if ($logline =~ /(.*)-->(.*)/) {
$DEVICE_CODE[$dfcnt] = $1;
$DEVICE_ANZAHL[$dfcnt] = $2;
print "DEVICE_final = $DEVICE_CODE[$dfcnt], D_ANZAHL_final = $DEVICE_ANZAHL[$dfcnt]\n";
if ($dfcnt > 0 ) {
if ( $DEVICE_CODE[$dfcnt] eq $DEVICE_CODE[$dfcnt-1] ) {
$DEVICE_ANZSUM = $DEVICE_ANZAHL[$dfcnt] + $DEVICE_ANZAHL[$dfcnt-1];
$DEVICE_ANZSUMZW = $DEVICE_ANZSUM++;
#$DEVICE_ANZSUM = $DEVICE_ANZAHL[$dfcnt]++;
#print "DEVICE_ANZAHL = $DEVICE_ANZAHL[$dfcnt],DEVICE_ANZAHL -1 = $DEVICE_ANZAHL[$dfcnt-1]\n";
print "DEVICE_eq = $DEVICE_CODE[$dfcnt], D_ANZAHL_eq = $DEVICE_ANZAHL[$dfcnt],DEVANZSUM = $DEVICE_ANZSUM,COUNT = $dfcnt\n";
}#end if
if ( $DEVICE_CODE[$dfcnt] ne $DEVICE_CODE[$dfcnt-1] ) {
#$DEVICE_ANZSUM=0;
#splice(#data3,$dfcnt+2,1) if ($DEVICE_ANZSUM > 1);
push (#data3,$DEVICE_ANZSUMZW) if ($DEVICE_ANZSUM > 1);
push (#data3,$DEVICE_ANZAHL[$dfcnt]) if ($DEVICE_ANZSUM == 0);
if ( $DEVICE_CODE[$dfcnt] ne $DEVICE_CODE[$dfcnt-1] ) {
$DEVICE_ANZSUM=0;
}
print "DEVICE_ne = $DEVICE_CODE[$dfcnt], D_ANZAHL_ne = $DEVICE_ANZAHL[$dfcnt], DEVANZSUM = $DEVICE_ANZSUM\n";
}#end if
}#end if $dfcnt
$dfcnt++;
}#end if logline
}#end for
print "#labels3\n";
print "#data3\n";
}#end sub read_final_dev_file
Probably not the best way, but this is what came to mind after seeing LeoNerd answer, since I don't have CPAN access in production and never have modules lying around:
#!/usr/bin/perl
use strict;
use warnings;
use Data::Dumper;
my #input = (
[ ccc => 2 ],
[ ccc => 5 ],
[ abc => 3 ],
[ abc => 7 ],
[ cb => 6 ],
);
my %output;
$output{$_->[0]} += $_->[1] for #input;
print Dumper \%output;
my #output = map { [ $_ => $output{$_} ] } keys(%output);
print Dumper \#output;
Output:
$VAR1 = {
'abc' => 10,
'cb' => 6,
'ccc' => 7
};
$VAR1 = [
['abc', 10],
['cb', 6],
['ccc', 7],
];
You could use List::UtilsBy::partition_by to group the original list into partitions, by the first string:
use List::UtilsBy qw( partition_by );
my #input = (
[ ccc => 2 ],
[ ccc => 5 ],
[ abc => 3 ],
[ abc => 7 ],
[ cb => 6 ],
);
my %sets = partition_by { $_->[0] } #input;
Now you have a hash, keyed by the leading strings, whose values are all the ARRAY refs with that key first. You can now sum the values within them, by mapping over $_->[1] which contains the numbers:
use List::Util qw( sum );
my %totals;
foreach my $key ( keys %sets ) {
$totals{$key} = sum map { $_->[1] } #{ $sets{$key} };
}
If you're inclined towards code of a more compact and functional-looking nature, you could instead use the new pairmap here; making the whole thing expressible in one line:
use List::UtilsBy qw( partition_by );
use List::Util qw( pairmap sum );
my %totals = pairmap { $a => sum map { $_->[1] } #$b }
partition_by { $_->[0] } #input;
Edit: I should add that even though you stated in your original question that the array was sorted, this solution doesn't require it sorted. It will happily take the input in any order.
You can simplify your subroutine a lot by using a hash to track the counts instead of an array. The following uses an array #devices to track the order and a hash %device_counts to track the counts:
my #devices;
my %device_counts;
while (<DATA>) { # Read one line at a time from DATA
if (/(.*)-->(.*)/) { # This won't extract newlines so no need to chomp
if (!exists $device_counts{$1}) {
push #devices, $1; # Add to the array the first time we encounter a device
}
$device_counts{$1} += $2; # Add to the count for this device
}
}
for my $device (#devices) {
printf "%s-->%s\n", $device, $device_counts{$device};
}

Create Chart using another worksheet in (Spreadsheet::WriteExcel::Chart) Perl module

I have started using Spreadsheet::WriteExcel::Chart for writing chart.I have 10 worksheet which contain data. I have added one worksheet for chart. My question is, How can I create chart using another worksheet data.
2) I also tried another approach In which,I have created new worksheet and load data from old worksheet than try to create chart.
3)In $data,we are hardcoding value, is it possible that can we fetch value from cell rather
than hardcode value
In both case,I am not able to figure out the solution.
use Spreadsheet::ParseExcel;
use Spreadsheet::WriteExcel;
use Spreadsheet::ParseExcel::SaveParser;
# Open the template with SaveParseir
my $parser = new Spreadsheet::ParseExcel::SaveParser;
my $workbook = $parser->Parse('DD1.xls');
if ( !defined $workbook ) {
die $parser->error(), ".\n";
}
#Create the New worksheet
my $Flop_workbook = Spreadsheet::WriteExcel->new('Flop.xls');
for my $worksheet ( $workbook->worksheets() ) {
my ( $row_min, $row_max ) = $worksheet->row_range();
my ( $col_min, $col_max ) = $worksheet->col_range();
my $worksheetname = $worksheet->get_name();
print "worksheetname : ", $worksheetname ,"\n";
my $sheet = $Flop_workbook->add_worksheet($worksheetname);
for my $row ( $row_min .. $row_max ) {
for my $col ( $col_min .. $col_max ) {
my $cell = $worksheet->get_cell( $row, $col );
next unless $cell;
print "Row, Col = ($row, $col)\n";
print "Value = ", $cell->value, "\n";
print "Unformatted = ", $cell->unformatted(), "\n";
$sheet->write_string($row,$col,$cell->value);
print "\n";
}
}
}
my $chartsheet = $Flop_workbook->add_worksheet('Chart_data');
my $chart = $Flop_workbook->add_chart( type => 'line' );
#Configure the chart.
$chart->add_series(
categories => '=SUM_F_SCDLIB_DFF!$I$2',
values => '=SUM_F_SCDLIB_DFF!$I$2',
); (Failed here As I need to load another worksheet data)
# Add the worksheet data the chart refers to.
my $data = [
[ 'Category', 2, 3, 4, 5, 6, 7 ],
[ 'Value', 1, 4, 5, 2, 1, 5 ],
];
$chartsheet->write( 'AB5', $data );
#$template->SaveAs('newfile.xlsx');

Why doesn't Perl's for() go through all of the elements in my array?

Have a perl brain-teaser:
my #l = ('a', 'b', 'c');
for (#l) {
my $n = 1;
print shift #l while (#l and $n --> 0);
print "\n";
}
What's it print? Should be a, b, and c, right? But oh wait actually there's a bug somewhere, it only prints a and b. Probably just some stupid off-by-one, should be easy to solve, right?
Ok so make a small code change to test things out and change #l to
my #l = ('a', 'b', 'c', 'd');
What's it print? Probably a, b, and c because of that stupid off by one, right? ...Wait a second, actually it still prints only a and b. Okay, so the bug is that it only prints the first two characters.
Change #l again to
my #l = ('a', 'b', 'c', 'd', 'e');
Uhm, now it prints a, b, and c. But not d or e. In fact, every 2 letters we add from now on will make it print the next letter in the sequence. So if we add f it'll still just print a, b, and c, but if we add f and g it'll print a, b, c, and d.
This also happens with similar results for different values of $n.
So what's going on here?
Dave Webb beat me to the problem, but here's a quote from perldoc perlsyn saying not to do it:
If any part of LIST is an array, foreach will get very confused if you add or remove elements within the loop body, for example with splice. So don't do that.
Note that, earlier in the text, the syntax of foreach was described as foreach LIST, which is the LIST they refer to in the documentation. Note also that foreach and for are equivalent.
What's going on is that you're using for and shift at the same time. So you're looping through the list whilst modifying it, not a good idea.
I think this is somebody's gadget code. It doesn't look like the way you would want to write anything. But what it might illustrate best is that (in at least some versions) Perl is really running a more basic for loop, where:
for ( #l ) {
#...
}
Is replaced by:
for ( my $i = 0; $i < #l; $i++ ) {
local $_ = $l[$i];
#...
}
Thus, because #l is ( 'c' ) when we've gone through twice, our trips through is already greater than scalar( #l ), so we're out. I've tested it out in a number of cases, and they seem to be equivalent.
Below is the code I wrote to test cases. From it we can see that because of the shift, as soon as we're halfway through, the loop will exit.
use strict;
use warnings;
use English qw<$LIST_SEPARATOR>;
use Test::More 'no_plan';
sub test_loops_without_shifts {
my #l = #_;
my #tests;
for ( #l ) {
push #tests, $_;
}
my #l2 = #_;
my $n = #tests;
my $i = 0;
for ( $i = 0; $i < #l2; $i++ ) {
local $_ = $l2[$i];
my $x = shift #tests;
my $g = $_;
is( $g, $x, "expected: $x, got: $g" );
}
is( $n, $i );
is_deeply( \#l, \#l2, do { local $LIST_SEPARATOR = .', '; "leftover: ( #l ) = ( #l2 )" } );
return $i;
}
sub test_loops {
my #l = #_;
my #tests;
for ( #l ) {
push #tests, shift #l;
}
my #l2 = #_;
my $n = #tests;
my $i = 0;
for ( $i = 0; $i < #l2; $i++ ) {
local $_ = $l2[$i];
my $x = shift #tests;
my $g = shift #l2;
is( $g, $x, "expected: $x, got: $g" );
}
is( $n, $i );
is_deeply( \#l, \#l2, do { local $LIST_SEPARATOR = ', 'c; "leftover: ( #l ) = ( #l2 )" } );
return $i;
}
is( test_loops( 'a'..'c' ), 2 );
is( test_loops( 'a'..'d' ), 2 );
is( test_loops( 'a'..'e' ), 3 );
is( test_loops( 'a'..'f' ), 3 );
is( test_loops( 'a'..'g' ), 4 );
is( test_loops_without_shifts( 'a'..'c' ), 3 );
is( test_loops_without_shifts( 'a'..'d' ), 4 );
is( test_loops_without_shifts( 'a'..'e' ), 5 );
is( test_loops_without_shifts( 'a'..'f' ), 6 );
is( test_loops_without_shifts( 'a'..'g' ), 7 );