Gossamer Forum
Home : General : Perl Programming :

Alphabetical sorting -- a bit more advanced

Quote Reply
Alphabetical sorting -- a bit more advanced
Following earlier guidance, I've been using the script below and variants with a good deal of success. I'm now trying to take things a bit further and would appreciate a little help!

My first
--------
On one script, I've got this filtering with alphabetical sort occuring twice (each working on a different field). To stop the second version repeating the values from the first, I've used a temporary

$dlist = "";

What's the correct command to reset $dlist to have no value?

My second
---------
For one of my lists, I need the filtering to pick out two fields per record (one field is displayed, the other is an HREF destination). As before, I want to work on the first field -- filtering out repeats of the same word/phrase and sorting alphabetically. Then I want to display the filtered fields, each linking to the page stated in the corresponding record's destination field.

Also, I'd like to exclude two specific field values from being displayed here (I will display them above the main alphabetical list).

I've tried looking through various scripts and reading up on-line guides, but being a newbie I'm at a loss how to make a list from a pair of fields and then call on the pair (and also how to exclude certain values from the list -- or from printing the list). Could someone please help with this scripting?

TIA,

Andy

-----------

Current script extract:

@words = split(/\s*\~~\s*/,$tabledata[0]);

foreach $aword (sort(@words)) {
push @filtered, ucfirst($aword) if ($dlist !~ /(^|\|)${aword}\|/);
$dlist .= $aword . "|";
}

foreach (sort(@filtered)) {
print "<option>$_</option>\n";
}



[This message has been edited by Andy (edited November 27, 1999).]
Quote Reply
Re: Alphabetical sorting -- a bit more advanced In reply to
 
#1
Code:
undef $something; # works too

#2
you can always do something like this
Code:
my %eg = (
"Gossamer-threads" => "http://www.gossamer-threads.com/",
"Yahoo!" => "http://www.yahoo.com/",
"Altavista!" => "http://www.altavista.com/"
);

foreach my $location ( sort keys %eg ) {
print qq|<a href="$eg{$location}">$location</a><br>\n|;
};

if that's something like what you're looking for...,


Quote Reply
Re: Alphabetical sorting -- a bit more advanced In reply to
Thanks!

I'm much happier with the "undef" than my simple =""

Thanks for the script. In trying to build up my knowledge, I tried something along the same lines -- but pulling the URL out of the database (as there will be several hundred records, each with its own URL field).

My attempt was something like:

foreach $tabledata[2] (sort $tabledata[2]) {
print qq|<a href="$tabledata[5]">$tabledata[2]</a><br>\n|;
};

but I didn't get it to work. For my current needs, I want to display the tabledata[2] values in alphabetical order, apart from two specific values (which I'll define in the script) which I want to exclude from the alphabetical list (as I'll print them out above the alphabetical list).

I'd appreciate any further ideas.

Thanks as ever,

Andy
Quote Reply
Re: Alphabetical sorting -- a bit more advanced In reply to
Hmm, that could probably wouldn't work.

What array holds all the links? Or what's your datasource? (such as the file you're using for all this)
Quote Reply
Re: Alphabetical sorting -- a bit more advanced In reply to
The datasource is a flatfile database of mine. The script reads each record fine (with a "while" statement using a counter) and splits out the fields with:

@tabledata = split(/\s*\|\s*/,$line,$fields);

Do I need an array to pull out the pairs of tabledata[2] and [5]? If so, I'm not sure how to do this (as I'm only just getting to grips with the above code)!

I hope I've answered your questions and do hope you can help.

Thanks again,

Andy
Quote Reply
Re: Alphabetical sorting -- a bit more advanced In reply to
Hmm, let me see if this is correct, you have a file that looks as follows:

something1|something2|Title|something3|something5|URL
something1|something2|Title|something3|something5|URL

?

In that case, probably something you'd want to do is like so:
Code:
#!/usr/bin/perl

# first read in the data
open FILE, "datafile";
while (<FILE> ) {
@row = split(/\s*\|\s*/,$line,$fields);
push @dataset, \@row;
};
close FILE;

# now sort and print the data
foreach $row ( sort { ${$dataset[$a]}[2]} <=> ${$dataset[$b]}[2] } @dataset ) {
print qq|<a href="$tabledata[5]">$tabledata[2]</a><br>\n|;
};

You can't sort on a single row, they have to all be in memory at the same time Wink
Quote Reply
Re: Alphabetical sorting -- a bit more advanced In reply to
Thanks, Kitsune.

I've managed to incorporate your suggested code into my script. All is working fine, except I'm getting a "no data" error on the following line:

foreach $tabledata ( sort { ${$dataset[$a]}[2]} <=> ${$dataset[$b]}[2] @dataset ) {

(I've used $tabledata in place of your $row as that's in my script already.)

Looking very closely at this, I think there might be a missing bracket, but my knowledge level isn't yet high enough to be able to work out how to sort this. May I trouble you to look at the line again, please?

Thanks alot,

Andy

----

Here's all the relevant code I'm now using:

&open_file("FILE1","","$basefile");
$line = &read_file("FILE1");
$counter = 1;
while (($line = &read_file("FILE1")) && ($counter < 100)) {

@tabledata = split(/\s*\|\s*/,$line,$fields);
push @dataset, \@tabledata;

$counter++;
};
close(FILE1);

foreach $tabledata ( sort { ${$dataset[$a]}[2]} <=> ${$dataset[$b]}[2] @dataset ) {
print "<A HREF=$tabledata[7]>$tabledata[2]</A><BR>\n";
};



[This message has been edited by Andy (edited December 04, 1999).]
Quote Reply
Re: Alphabetical sorting -- a bit more advanced In reply to
Yes, a } is missing:

foreach $tabledata ( sort { ${$dataset[$a]}[2]} <=> ${$dataset[$b]}[2] }@dataset ) {

Baris.

------------------
Turk Scripts
http://turkiyem.com/turkscripts
Quote Reply
Re: Alphabetical sorting -- a bit more advanced In reply to
Thanks, sumengen.

I really appreciate all the guidance I've received here.

Andy
Quote Reply
Re: Alphabetical sorting -- a bit more advanced In reply to
I've now tested and hit another error.

Racking my brains, I've thought to print out the value of $dataset[2], which produces:

ARRAY(0xc4320)

-- leaving me totally confused.

Is it clear what's wrong or is there something else I can do do test and pick out my errors? All the relevant code is in my earlier posting.

TIA,

Andy

[This message has been edited by Andy (edited December 04, 1999).]
Quote Reply
Re: Alphabetical sorting -- a bit more advanced In reply to
kitsune if you use undef in a use strict script.. won't it give you an error?

the case is for when deleting the content of a scalar.. just say this was part of a use strict script:

Code:
my ($hi);
$hi = "hello";
undef $hi;
$hi = "bye";

that would give you an error.. correct?

so it would be smart to use the simple way

$dlist = "";

right?? Smile

jerry
Quote Reply
Re: Alphabetical sorting -- a bit more advanced In reply to
andy.. when you push an array into another array like this

push @anotherarray, \@array

the structure of the array is sorta like this

@anotherarray = (
['the','content','of','the','first','pushed'],
['the','content','of','the','second','pushed'],
['the','content','of','the','third','pushed']
);

etc..

anyways.. so when you say $anotherarray[2]

you get the array ['the','content','of','the','third','pushed']

that is why it returns that..

i'm not exactly sure what to do here.. i've only worked with hash arrays..

but in hashes you do this

$hashname->{'Field'}[0]

equilvalent to

${$hashname}{'Field'}[0]

(for printing)..

what it seems like you'd need to do is like

${$anotherarray[0]}[0]

but i've never tried it that way..

the easy way is

Code:
@thisline = @{$anotherarray[0]}
print $thisline[2];

jerry

[This message has been edited by widgetz (edited December 04, 1999).]
Quote Reply
Re: Alphabetical sorting -- a bit more advanced In reply to
You're probably right, I'm relatively new (1 year or so) to perl, so that hat goes to you.

However, I tried to use strict on that code fragment you wrote and it seemed to work.

I should read the man pages, are there any other reasons undef shouldn't be used? I use undef fairly extensively as my hashes tend to accumulate (they're used for caching) and I need to dispose of them immediately after their purpose has ended

whupsie, sorry andy, any luck with your script yet? Wink
Quote Reply
Re: Alphabetical sorting -- a bit more advanced In reply to
usnig $variable = undef; will not produce an error under strict.

Andy, your receiving that output because it appears you are tying to print a reference. I could be wrong though. Can you show us the snippet of code where you are doing that?

--mark

------------------
Due to repeated requests for support via ICQ, I am once again offering support online.

The ONLY number I will accept requests on is #53788453. Messages sent to my other numbers will not pass through to me, as I have security settings set to ignore messages from users not on that list.

I don't know how often I will be active on this number, as it is for only when I am free to offer assistance.

Could this signature be any longer? :)
Quote Reply
Re: Alphabetical sorting -- a bit more advanced In reply to
Using undef worked just fine. Before that, the $variable="" resulted in the previous array being exluded but gave me one extra blank line which I didn't want.

In my script, I've got three arrays. The first one lists alphabetically (and dropping out any repeats) the (country) names listed in tabledata[2] as follows:

@tabledata = split(/\s*\|\s*/,$line,$fields);
@words = split(/\s*\~~\s*/,$tabledata[2]);

foreach $aword (sort(@words)) {
push @filtered, ucfirst($aword) if ($list !~ /(^|\|)${aword}\|/);
$list .= $aword . "|";
}

$counter++;
} # end of 'WHILE' loop

close(FILE1);

#print the filtered list of words
foreach (sort(@filtered)) {
print "<option>$_</option>\n";
}

The second piece of script repeats the above on another field. In between the two, I've used:

undef @filtered

to avoid names from the first part being listed in the second part.

This all worked fine. Now I've added the third part of the script which uses different variables (and I took it that undef had no effect on this third section). In each of the three sections, I close the file reading and start it up again.

Here's all the relevant code for the third part:

&open_file("FILE1","","$basefile");
$line = &read_file("FILE1");
$counter = 1;
while (($line = &read_file("FILE1")) && ($counter < 100)) {
@tabledata = split(/\s*\|\s*/,$line,$fields);
push @dataset, \@tabledata;
$counter++;
};
close(FILE1);

foreach $tabledata ( sort { ${$dataset[$a]}[2]} <=> ${$dataset[$b]}[2] @dataset ) {
print "<A HREF=$tabledata[7]>$tabledata[2]</A><BR>\n";
};

Am I making things difficult by trying to create an array on pairs of fields? I tried the easier route of storing in the script the values of tabledata[7] which match tabledata[2], but users can update the database so I have to look to that as my source.

Hoping I've clarified the situation and hoping things are a lot clearer to you folk than they are to me!!

All the best,

Andy

[This message has been edited by Andy (edited December 05, 1999).]
Quote Reply
Re: Alphabetical sorting -- a bit more advanced In reply to
andy.. change this line:

Code:
print "<A HREF=$tabledata[7]>$tabledata[2]</A><BR>\n";

to

Code:
print "<A HREF=$$tabledata[7]>$$tabledata[2]</A><BR>\n";

if that doesn't work Wink then put this above the ORIGINAL line..

Code:
@tabledata = @{$tabledata};

jerry
Quote Reply
Re: Alphabetical sorting -- a bit more advanced In reply to
Jerry, thanks for this.

I've tried the $$ version and then the original $ version with the extra line of code you gave me. Again, I'm hitting a "No Data" error.

I avoid the error if I hide the following loop:

foreach $tabledata ( sort { ${$dataset[$a]}[2]} <=> ${$dataset[$b]}[2]} @dataset ) {
}

Does that prove that there's still an error in this line or that the previous code hasn't created any $tabledata or $dataset values?

Thanks,

A
Quote Reply
Re: Alphabetical sorting -- a bit more advanced In reply to
I've been trying another way round this -- with two database lookups, one after the other. Only to get in more of a mess!

Does anyone have any ideas on how to get the above script working ... or perhaps of another way round?

TIA,

A
Quote Reply
Re: Alphabetical sorting -- a bit more advanced In reply to
I want to mention a new aproach which doesn't use references.

%lines = map{$_,( split /\s*\|\s*/)[2]}@lines;

#Now sorting acccording to the third column
@sorted_lines = sort{ $lines{$a} cmp $lines{$b} }(keys %lines);

# Now we have the sorted lines (according to the third column). Now do whatever you want.

------------------
Turk Scripts
http://turkiyem.com/turkscripts
Quote Reply
Re: Alphabetical sorting -- a bit more advanced In reply to
Thanks for the new approach. With a lot of thought, I'm starting to understand this. But obviously not enough just yet to call the results I want! I think the script below should work -- but could you please correct where I've gone wrong.

TIA,

Andy

----------------------------------------

&open_file("FILE1","","$targetfile");

$line = &read_file("FILE1");
$counter = 1;

while (($line = &read_file("FILE1")) && ($counter < 100)) {

%lines = map {$_,( split /\s*\|\s*/)[0]}@lines;

# Now sorting according to the first column
@sorted_lines = sort{ $lines{$a} cmp $lines{$b}} (keys %lines);

print "<TR valign=top><TD ALIGN=center>\n";
print "<A HREF=$sorted_lines[7]>$sorted_lines[0]</A>\n";
print "</TD></TR>\n";

$counter++;

};

close(FILE1);
Quote Reply
Re: Alphabetical sorting -- a bit more advanced In reply to
The elements of the array, @sorted_lines are lines. You have to use split() on each of the elements of the @sorted_lines.


------------------
Turk Scripts
http://turkiyem.com/turkscripts
Quote Reply
Re: Alphabetical sorting -- a bit more advanced In reply to
Thanks for this. You've helped me better appreciate what's going on. I now understand that the array, @sorted_lines comprises a series of lines, each of which contains fields numbered 0|1|2|3 etc. I take it that this is just the same as reading a file and creating an array of:
@tabledata = split(/\s*\|\s*/,$line,$fields);

I don't quite grasp how a split() of $sorted_lines would help me. I can see how I'd use split() to extract, say, the values of field 0 across all the lines. But I can't see how to use split() to pick out the pairs of values I want (fields 0 and 7).

I'm thinking that the following should work (placed after closing the "read" loop):

foreach $sorted_lines {
print "<TR valign=top><TD ALIGN=center>\n";
print "<A HREF=$sorted_lines[7]>$sorted_lines[0]</A>\n";
print "</TD></TR>\n";
};

The foreach $sorted_lines causes an error, which suggests I haven't grasped the distinction between the two arrays, @tabledata and @sorted_lines.

Sorry for being so slow!

All the best,

Andy
Quote Reply
Re: Alphabetical sorting -- a bit more advanced In reply to
foreach $sorted_line (@sorted_lines) {
@elements_of_line = split(/\s*\|\s*/,$sorted_line,$fields);
print "<TR valign=top><TD ALIGN=center>\n";
print "<A HREF=$elements_of_line[7]>$elements_of_line[0]</A>\n";
print "</TD></TR>\n";
};


Baris.

------------------
Turk Scripts
http://turkiyem.com/turkscripts
Quote Reply
Re: Alphabetical sorting -- a bit more advanced In reply to
Thanks again. I've tweaked the above to amend my code and -- with a fair amount of learning by trial and error -- I've eventually got my script to produce some results. Unfortunately, the results are not yet the ones I want! The "test print" line in the script below shows fields 27 and 63 in place of 7 and 0.

While I've learned alot by working on this, I'm not totally on top of it to know where I've made errors which prevent my desired result of matched pairs (of fields 7 and 0) which are sorted alphabetically by the value in field 0.

I hope I'm not being too much bother by asking for pointers on my script below.

BTW, I've checked my full script in detail (eg for the value of $fields). Yet other sections of the script (which produce lists and drop-down menus from the same database) are working fine.

TIA,

Andy


* * * * * * * * * * *

Latest code:

&open_file("FILE1","","$basefile");

$line = &read_file("FILE1");
$counter = 1;
$fields = 73;

while (($line = &read_file("FILE1")) && ($counter < 300)) {

# split the fields at the | character
@tabledata = split(/\s*\|\s*/,$line,$fields);

if (($in{'jump'} eq "$tabledata[2]") && ($tabledata[5] =~ /^Yes/i)) {
%tabledata = map {$_,( split /\s*\|\s*/)[0]}@tabledata;

# Now sort according to the first column
@sorted_lines = sort{ $tabledata{$a} cmp $tabledata{$b}} (keys %tabledata);

# TEST PRINT
print "$sorted_lines[7]:$sorted_lines[0]<BR>\n";

}; # end of if condition

$counter++;

}; # end of WHILE routine

close(FILE1);


# now print the results

foreach $sorted_line (@sorted_lines) {
@elements_of_line = split(/\s*\|\s*/,$sorted_line,$fields);

print "<TR valign=top><TD ALIGN=center>\n";
print qq|<A HREF="$elements_of_line[7]">$elements_of_line[0]</A>\n|;
print "</TD></TR>\n";

}; # end of "foreach" routine

[This message has been edited by Andy (edited January 15, 2000).]