Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations John Tel on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

sort file

Status
Not open for further replies.

Guest_imported

New member
Jan 1, 1970
0
I need sort a flat file on one field. Seems like very simple, but it doesn't work for me. When i print out the datafile, the sorted file is same as the original one. I have no idea what i did wrong. Please help!! Thanks!
the following is my script:

my @data;
while ($line = <IN>){
push @data, ( split(/\[\w*\]+/, $line)) ;
}
print &quot;@data<br>\n&quot;;

my @sorted = sort{$a->[1] <=> $b->[1]} @data ;

print &quot;@sorted\n&quot;;

 
It needs to turn the (split ...) into an arrayref. Brackets added:
[tt]
push @data, [ (split(/\[\w*\]+/, $line)) ];
[/tt]

will do that. Then your sort block will work as it stands. &quot;If you think you're too small to make a difference, try spending a night in a closed tent with a mosquito.&quot;
 
Thank you!!
But why can't I print my data out. when I tried to print it, nothing came out. but I got the memory location.

my @data;
while ($line = <IN>){
push @data, [( split(/\[\w*\]+/, $line))] ;
}
#print &quot;@data<br>\n&quot;;

my @sorted = sort{$a->[6] <=> $b->[6]} @data ;

#print &quot;@sorted\n&quot;; #will get ARRAY(0x807f664) etc.

#@sorteddata = @$sorted;
#print &quot;@sorteddata\n&quot;; #nothing be printed

print &quot;@{$sorted}\n&quot;; #nothing come out

 
because it's a reference to the actual arrays, not the data itself. each element is an array ref, so the actual data has to be dereference once per row:[tt]
map {print @{$_}, &quot;\n&quot;} @sorted;
print &quot;<br>\n&quot;;
[/tt]

also, the array '@sorted' is an actual array, you don't need to dereference it, in fact, trying to dereferencing it as you did produces no output(as you found out). also, in case it isn't clear, the 'map' statement about works about the same as a 'foreach' loop, if you'd prefer that syntax. either way, you have to be sure to iterate over all the elements of the array, dereferencing as you go.
good luck &quot;If you think you're too small to make a difference, try spending a night in a closed tent with a mosquito.&quot;
 
Got a problem , need your help again!!!
How can I get the new sorted array with the same format as my original one? my test file only has six field, now I can even get $new[20]. It means my whole file now has only one record.

my @data;
while ($line = <IN>){
push @data, [( split(/\[\w*\]+/, $line))] ;
}

my @sorted = sort{$a->[1] cmp $b->[1]} @data ;

@new = map {@{$_},&quot;\n&quot;} @sorted;

print &quot;<br>$new[20]\n&quot;; #in my original file, only has 6 fields.now it prints out the
#the third field of the third record.
print &quot;<br>@new\n&quot;;
 
Err... I do not understand the intent of the line:[tt]
print &quot;<br>$new[20]\n&quot;;[/tt]

Original form means one of two things. Either you mean back into a flatfile database, or into the format you were originally trying to read it in as. I doubt you want it back into the flatfile format, but i'm not sure why you would want it in the original format you were reading it in as. The data is all there to be manipulated however you need, you'll just have to dereference each row to get at it's entries. reading &quot;perldoc perlref&quot; could help you become more aquainted with how to do this. In your case, though, it would be as easy as &quot;$sorted[3][0]&quot; or
&quot;$sorted[5][2]&quot; or whatever numbers corresponded to the row number (minus 1) and the entry number (minus 1), in that order.
However, if you just want the exact form your original script read it into:[tt]
@old_format = map {@{$_}} @sorted;[/tt]

all you were doing wrong was the &quot;\n&quot; of mine was intended to be printed, otherwise it adds an extra (and useless, now that i think about it. the original newlines from the file were left in) entry for every row, thus throwing off your count.
 
Hi, I am sorting file by date now, but couldn't get the correct result. If I sort by any other values, it works fine. So I think the problem is the converttime function. But I can't figure out what I did wrong.
Please help!!!!
Thank you.

my @data;
while ($line = <IN>){
push @data, [( split(/\[\w*\]+/, $line))] ;
}

my @sorted =
sort { &converttime($a->[22]) <=> &converttime($b->[22])} @data ;

#print out all the records in the file, they are sorted by the activedate

foreach (@sorted) {
$listing = &quot;$_->[22],
$_->[2],
$_->[3],
$_->[4],
$_->[5],
$_->[6]
$_->[7]&quot;;

print &quot;$listing<br>\n&quot;;
}

# convert m/d/y format into Perl's seconds-since-1900 format. I have # include theTime::Local module

sub converttime {
my $date;
if ($date eq &quot;&quot;) { #error formatting , sort to top. this part doesn't work #either,if the $date is empty, that record won't show up #in my print list.
return 0;
} else {
my ($m,$d,$y) = split(/\//,$date);
$m--;
return timelocal(0,0,0,$d,$m,$y);
}
}


 
your problem is a simple oversight: the first line of your &convertdate should be:[tt]

my $date = shift or return 0;[/tt]


the '= shift' part is all you really need, but i put the 'or return 0' part in because then you can skip the if/else statement below it (for the assignment of $date, if it's &quot;&quot;, that will evaluate to false, causing the 'return 0' part to be executed), turning it into:[tt]

sub convertdate
{
my $date = shift or return 0;
my ($m,$d,$y) = split(/\//,$date);
$m--;
return timelocal(0,0,0,$d,$m,$y);
}[/tt]
&quot;If you think you're too small to make a difference, try spending a night in a closed tent with a mosquito.&quot;
 
It doesn't work. After I changed it into &quot; my $date = shift ;&quot;, I got a &quot;server error&quot; message on the browser, but there is no problem when I run it under UNIX.
Why I need use the shift function?
Thanks a lot!
 
I found out that the problem could be
my @sorted =
sort { &converttime($a->[22]) <=> &converttime($b->[22])} @data;
because when I tried to print out $date in converttime(), if it is &quot;my $date;&quot;
nthing will be printed out, $date is empty. If it is &quot;my $date = shift:&quot; got server error(I guee since there is nothing being passed to the function, so can't do the shift)
Is it the right way to call a function in the reference like this?
If I don't call the function converttime(), it'll sort the file by the $m $d $y. Of course that is not what I want. I want it sorted by $y $m $d.
Looking forward to hearing from you!!!
Thank you.
 
hrmm..
first question first. the '=shift' part is because when you call the subroutine, you're passing it an argument. that argument gets brought into the sub as the array '@_'. since you need to use the data that's being passed into the subroutine, you need to get that data out of the array and use it (you could even leave it in, and just reference it as $_[0], but that's a little too cryptic and sloppy). when more arguments are passed, the array will of course have more entries. well, anyway, the '=shift' part makes '$data' have the value that the first element of that array has, which is what you want.
now, as to the server error... i don't know. if it is as you say, and it runs fine on the command line, but fails in the browser, it may be improper permissions on a file used or some problem involving database accessing (which you aren't doing)
however, since you say this problem has only occurred due to the recent changes you have made, and that specifically the line '=shift' is causing it, i can't say.
what is the exact text of the sub as it currently stands? is it the one i wrote, or different. my subroutine compiles and works fine on my system. even if there's nothing to be passed to it, that'll just cause the subroutine to return zero (that's another benefit of the 'or return 0;' part)
it could be that the syntax of the dates isn't in the format you think it is (it may have spaces or something in it that you'll need to remove or avoid), but at this point, i don't have enough information to diagnose your problem.
sorry. &quot;If you think you're too small to make a difference, try spending a night in a closed tent with a mosquito.&quot;
 
stillflame:
Thank you. You are great!!!!!!!!
You are right. the problem is the syntax of the date. When I use a simple file to test the code, it works fine.
My data file has thousands of records. some of them are in the format like 01-03-00, some of them are empty. I hasn't finished the checking, but now I know they are not all in the standard format. I am trying to find a way to avoid all these unstandard date and sort them to the top:

sub convertdate {
my $date = shift ;
if ($date =~ /\/*\/*\/*/ ) {
my ($m,$d,$y) = split(/ \/ /,$date);
$m--;
return timelocal(0,0,0,$d,$m,$y);

}
else
{
return 0;
}

}

it works on command line, but got &quot;server eorror&quot; message on the browser.
is $date =~ /\/*\/*\/*/ right for the */*/*/ format? what is the best way to do this job? Correct the file record first, or just sort them to the top. How to sort all the unstandard date to the top?
Thank you.

 
a regex for mm/dd/yy is:
[tt]m~(\d+?)\/(\d+?)\/(\d+?)~[/tt]
which then assigns the three numbers to $1, $2, and $3. so you would then say:
[tt]($m, $d, $y) = ($1, $2, $3);[/tt]

if it's feasable to standardize the dates in all the records, you can do that. but that doesn't prevent this from happening again. you could create a subroutine that converts all the known types of formats into a single standard format. this subroutine could then be used both to convert every date on file to the standard, or it could be used to convert them on the fly, or (preferably) both. this would be a regex intense operation to undertake, but would make your code much more flexable.

good luck. &quot;If you think you're too small to make a difference, try spending a night in a closed tent with a mosquito.&quot;
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top