sandy105 has asked for the wisdom of the Perl Monks concerning the following question:
i had to write a csv sorting code for which i used the following code :
foreach(@files){
if(/\.csv$/i) { # if the filename has .csv at the end
push(@csvfiles,$_);
}
}
foreach(@csvfiles) {
$csvfile=$_;
open(hanr, "D:\\stock\\".$csvfile)or die"error $!\n";
open(hanw , ">D:\\stock\\sorted".$csvfile) or die"error $! \n";
@lines=();
@lines=<hanr>;
foreach $line (@lines){
chomp $line;
$count++;
next unless $count; # skip header in csv
my $row;
@$row = split(/,/, $line );
push @$sheet2 , $row;
}
foreach my $row (
sort { $a->[0] cmp $b->[0] || $a->[1] cmp $b->[1] } @$sheet2
)
{
chomp $row;
print hanw join (',', @$row ),"\n";
}
@$sheet2 = ();
$count = -1;
close(hanw);
close(hanr);
}
however i do not understand what @$row is ..also i understand sorting a NORMAL array @sheet2 comparing coulumn 0 and 1 ..but i cannot understand what is the state of @$row and $ row being pushed into @$sheet2; if someone would explain the whole thing it would be wonderful:
@$row = split(/,/, $line );
push @$sheet2 , $row;
}
foreach my $row ( sort {$a->[0] cmp $b->[0] || $a->[1] cmp $b->[1]} @
+$sheet2 )
{
*print hanw join (',', @$row ),"\n";
}
Re: what is @$varname in perl
by choroba (Cardinal) on Jul 03, 2014 at 08:52 UTC
|
Crossposted at StackOverflow. It is considered polite to inform about crossposting so people not attending both sites don't waste their time hacking a problem already solved at the other end of the Internet.
| [reply] [Watch: Dir/Any] |
|
| [reply] [Watch: Dir/Any] |
|
The convention is not specific to PerlMonks nor to Perl. It is basic politeness to inform the readers of any forum that you have solicited responses in other places as well so that the readers do not waste their valuable time presenting solutions which have already been discussed elsewhere.
So, other than PerlMonks and SO, where else have you asked this question?
| [reply] [Watch: Dir/Any] |
|
Re: what is @$varname in perl
by AppleFritter (Vicar) on Jul 03, 2014 at 09:13 UTC
|
$row is an array reference (sort of like a pointer in C); @$row is the actual (anonymous) array it references. The same goes for $sheet2 and @$sheet2.
What the code is essentially doing is to read each file line by line, split each line along commas, and store everythign in an array of arrays. So, for instance, the following file:
Name,Level,Writeups,XP
Corion,Pope (28),8574,108561
Grandfather,Cardinal (24),6205,67751
Athanasius,Prior (17),773,11777
AppleFritter,Pilgrim (8),92,784
would be turned into this data structure:
$VAR1 = [
[
'Corion',
'Pope (28)',
'8574',
'108561'
],
[
'Grandfather',
'Cardinal (24)',
'6205',
'67751'
],
[
'Athanasius',
'Prior (17)',
'773',
'11777'
],
[
'AppleFritter',
'Pilgrim (8)',
'92',
'784'
]
];
This is then used to sort the file on the first two columns.
| [reply] [Watch: Dir/Any] [d/l] [select] |
|
thank you but its still not clear, so @{$row} contains that data structure and @{$sheet2} is pushed $row the reference .
i was reading into undefined and reference but still am confused ..refrences are declared like this i saw .
could you take out time and give clarity to the undefined $row ,@$row , and what $row being pushed to @$sheet2 means
my @array = (1, 2, 3, 'four');
my $reference = \@array;
| [reply] [Watch: Dir/Any] [d/l] |
|
I'm not entirely sure what your question is, or where the confusion lies. Could you clarify?
As I said above, references are sort of like pointers in C, if you're familiar with that. A data structure lives somewhere in memory; another variable, a scalar (which might in turn be an element of an array or hash, of course) holds a reference to it. A redirect, if you will: "the data you're looking for is found in another location. Walk this way!"
Programming Perl has an entire chapter on references, so if you've got that book, I'd read that. (If you don't have that book, buy it, it's a must-have for any Perl programmer.) Also, see perlref for a less gentle introduction.
Anyhow, to sum it up:
- $row contains (colloquially: is) a reference to an array, i.e. the one that split returns.
- That array does not have a name of its own; i.e., it's not @array or any such thing.
- However, you can use the reference in $row -- "walk this way", as it were, following the directions it contains -- by dereferencing the reference. For an array reference, this is done by adding the array sigil, @: @$row.
- The same applies to $sheet2 and @$sheet2.
- Finally, @$sheet2 -- an array, remember! -- is used to store a list of references, each of which points to another array: one for each row.
So you have something like this for each line:
$row @$row
+---+ +-----+-----+-----+--
| *-----> | ... | ... | ... | ...
+---+ +-----+-----+-----+--
and something like this for the entire file:
$sheet2 @$sheet2 (each of the @$row's)
+---+
+---+ | | +-----+-----+-----+--
| *-----> | *-----> | ... | ... | ... | ...
+---+ | | +-----+-----+-----+--
+---+
| | +-----+-----+-----+--
| *-----> | ... | ... | ... | ...
| | +-----+-----+-----+--
+---+
| . |
.
Does that make it clearer?
| [reply] [Watch: Dir/Any] [d/l] [select] |
|
|
|
Re: what is @$varname in perl
by perlfan (Vicar) on Jul 03, 2014 at 11:34 UTC
|
It seems like you're writing your arrays as array references just so you can avoid creating a reference out of a non-reference.
You have:
foreach $line (@lines){
chomp $line;
$count++;
next unless $count; # skip header in csv
my $row;
@$row = split(/,/, $line );
push @$sheet2 , $row;
}
But if you ask me, it'd be tons more clear if you did this:
my @sheet2 = ()
# ....
foreach $line (@lines){
chomp $line;
$count++;
next unless $count; # skip header in csv
my @row = ();
@row = split(/,/, $line );
push @sheet2 , \@row;
}
Another example is:
@$sheet2 = ();
Should be:
@sheet2 = ();
or
$sheet2 = [];
It seems to me you're conflating scalars, arrays, and references. Cleaning up the code and being consistent will go a long way in dispelling your confusion. | [reply] [Watch: Dir/Any] [d/l] [select] |
|
my @array = (1, 2, 3, 'four');
my $reference = \@array;
i modified using your suggestion as below
foreach $line (@lines){
chomp $line;
$count++;
next unless $count;
my @row = ();
@row = split(/,/, $line );
push @sheet2 , \@row;
}
foreach my $row ( sort {$a->[0] cmp $b->[0] || $a->[1] cmp $b-
+>[1]} @sheet2 ) #sorting based on date ,then stockcode
{
chomp $row;
print hanw join (',', @$row ),"\n";
}
then why assign @sheet2 as reference
| [reply] [Watch: Dir/Any] [d/l] [select] |
|
...
my $row;
@$row = split(/,/, $line );
push @$sheet2 , $row;
...
OR
...
my @row = ();
@row = split(/,/, $line );
push @sheet2 , \@row;
...
Could be written like this in one line instead of three
...
push @sheet2, [ split(/,/, $line ) ];
...
And there is no need for the array variable row at all.
You could use Data::Dumper to view your variable @sheet2 to confirm.
If you tell me, I'll forget.
If you show me, I'll remember.
if you involve me, I'll understand.
--- Author unknown to me
| [reply] [Watch: Dir/Any] [d/l] [select] |
|
push @sheet2 , \@row;
You're pushing a reference to @row as an item into @sheet2. In order to create complex data structures (array of arrays, array of hashes, etc) you need to assign references. | [reply] [Watch: Dir/Any] [d/l] |
Re: what is @$varname in perl
by Anonymous Monk on Jul 03, 2014 at 09:00 UTC
|
$ ppi_dumper 2
PPI::Document
PPI::Statement
PPI::Token::Cast '@'
PPI::Token::Symbol '$sheet2'
PPI::Token::Whitespace '\n'
See perldoc PPI::Token::Cast :P | [reply] [Watch: Dir/Any] |
Re: what is @$varname in perl
by 2teez (Vicar) on Jul 03, 2014 at 10:06 UTC
|
Hi sandy105,
..however i do not understand what @$row is.. and YET you had the code above written? That doesn't add up for me.
More so, if you have to deal with CSV files, think of using either Text::CSV_XS or Text::CSV than hand-picking commas using split and others.
If you tell me, I'll forget.
If you show me, I'll remember.
if you involve me, I'll understand.
--- Author unknown to me
| [reply] [Watch: Dir/Any] |
|
my @arr = split(/,/, $line );
my $row = \@arr;
Regards, | [reply] [Watch: Dir/Any] [d/l] |
|
| [reply] [Watch: Dir/Any] |
|
"i had to write a csv sorting code for which i used the following code :"
i wrote this multithreaded program to sort files in parallel ,this was actually the subroutine part (sort of).initial code which i tried would append sorted line to previous line, so 2 lines would be clubbed in 1 line ; hence i found THIS code on net
initial code below
foreach(@csvfiles) {
$csvfile=$_;
open(hanr,"D:\\stock\\".$csvfile) or die"error read $!\n";
open(hanw,">D:\\stock\\sorted".$csvfile) or die"error write $!\n";
@lines = ();
@lines = <hanr>;
shift(@lines);#remove header csv
@sorted = sort multisort @lines;
sub multisort {
($field1a, $field2a, $field3a)=split(/\,/, $a);
($field1b, $field2b, $field3b)=split(/\,/, $b);
$field1a cmp $field1b or $field2a cmp $field2b;
}
print hanw @sorted;
close(hanw);
close(hanr);
}
| [reply] [Watch: Dir/Any] [d/l] |
|
Well, the above code makes sense. Maybe it is not very efficient because it splits lines inside of the sort, but it should work.
It looks like you don't know perl, so it is bad idea to write in perl when you don't know it. So either learn it, or ask someone to write the code that you need. For that, specify exactly what the code should do.
It's just hard to answer random questions about perl, when the listener does not know much about it. Without ground knowledge the answers won't make sense.
| [reply] [Watch: Dir/Any] |
|
|
|
|
Re: what is @$varname in perl
by Myrddin Wyllt (Hermit) on Jul 03, 2014 at 14:37 UTC
|
Not directly related to the reference / dereference question, but if your csv files do have header rows, your check on $count won't skip them, as you increment before you test (so $count will always be true). If you need to skip the headers, make $count local to the file loop (rather than global), and increment after the test.
| [reply] [Watch: Dir/Any] |
|
| [reply] [Watch: Dir/Any] |
|
|