in reply to Perl modules or standard tools for searching hierachical data

Basically I need to create a list of values in the correct order so that a "dependent" is always loaded after the parent otherwise the load simply will not work.

It took me a while to get my head around the issue, but I think it's accurate to rephrase it like this:

In order for the data set to be loaded correctly as a whole, records containing top-level parents must be loaded before those containing intermediate parents. In other words, whenever a given value is first seen in the "parent" column, insertion of that record must be deferred until either:

  1. it is established that this value never occurs as the "child" in another record, or
  2. the record containing this value as "child" has already been stored to the database.
(Meanwhile, records having the same value as both parent and child may be loaded at any time in the sequence.)

Supposing that's right, here's a demonstration on a small sample data set, using a hash structure to keep track of parent and child relations for each field value, and a recursive function to print out the records in the order required. (Recursion is not needed to load the hash.)

All this does is sort the input lines into the desired order (if a value serves as both child and parent, the record that has the value as child always comes first). This works well for loading the database, because you'll probably want to use whatever native loader is available for the particular database server you're using (inserts via DBI are very slow in comparison).

#!/usr/bin/perl use strict; use warnings; my %node; while (<DATA>) { my ( $c, $p ) = split; if ( $c eq $p ) { # these are easy, so finish them first print; next; } if ( exists( $node{$c}{child_of} )) { warn "$.: bad record: $c is child of both $p and $node{$c}{chi +ld_of}\n"; next; } $node{$c}{child_of} = $p; $node{$p}{parent_of}{$c} = undef; } # begin the sorted output by looping over values that do not have pare +nts: for my $parent ( grep { !exists( $node{$_}{child_of} ) } keys %node ) +{ my $children = $node{$parent}{parent_of}; # ref to hash of child +values trace_down( $children, \%node ); } sub trace_down { my ( $kids, $tree ) = @_; for my $kid ( keys %$kids ) { print "$kid $$tree{$kid}{child_of}\n"; if ( exists( $$tree{$kid}{parent_of} )) { trace_down( $$tree{$kid}{parent_of}, $tree ); } } } __DATA__ n1 n2 n3 n2 n4 n1 n5 n5 n6 n4 n7 n7 n8 n9 n10 n2 n11 n6 n2 n12 n7 n6 n8 n4
Note that I took the liberty of enforcing a "one-parent-only" constraint (the last line of DATA causes a warning, and is ignored). But I wasn't clear about the status of values that occur as both parent and child in a single record. (Should the next-to-last line of DATA cause a warning as well?) The special treatment of the "child eq parent" records might be problematic...

(Update: moved the line in the main "while" loop that stores the "parent_of" relation, so that it happens after the "one-parent-only" condition has been passed; if it happens before that check, it puts a redundant entry in the hash structure.)

Replies are listed 'Best First'.
Re^2: Perl modules or standard tools for searching hierachical data
by SlackBladder (Novice) on Mar 13, 2007 at 11:12 UTC
    Now I know I am a PERL "novice" !!
    Thank you for the "wisdom" graff.
    I have updated my code so that the original stuff I had (data extraction from SQL Server using "Win32::SqlServer") can be used by the code you kindly supplied. I think that it's a excellent base but after checking the result set I think that perhaps I did not do a good job of describing some "irregularities" in the data set.
    For example, the text "A1-910-ES-002B" can be found as a parent to "A1-910-ES-002B-16" (the actual record is)
    A1-910-ES-002B-16|A1-910-ES-002B (pipe symbol is the delimiter).
    Unfortunately, the text "A1-910-ES-002B" is also found in the child number "A1-910-ES-002B-17", which has a parent of "A1-910-ES-002B" (full record is)
    A1-910-ES-002B-17|A1-910-ES-002B
    I have a sneaking suspicion that the grep command is matching not only the text in isolation but any line that has that text in it.
      I have a sneaking suspicion that the grep command is matching not only the text in isolation but any line that has that text in it.

      If there's a problem, I don't think it involves the grep operation in the code I suggested. In the "for" loop over top-level parents, the grep does not involve a regex match, and is not susceptible to "false-alarm" substring matches. It is only returning the keys for those elements in the %node hash that are not the children of other nodes. Hash key lookups are always based on exact matches -- "abc" does not match "abcd" as a hash key.

      The two sample records you cited involve two child values having the same parent value, so if I understand what you've said so far, their ordering relative to each other should not matter. If that parent value happens to be the child in some other record, it would matter to have that other record output before these two.

      Since you have pipe-delimited data, I'm assuming you've extracted the data from the older server into a text file, and you're reading from that file in order to sort it, which makes perfect sense. Of course, my code would need to be adjusted slightly for pipe-delimited input instead of space-delimited:

      while (<DATA>) { chomp; my ( $c, $p ) = split /\|/; ... # update: also need to change the print statement in sub trace_down(): ... print "$kid|$$tree{$kid}{child_of}\n"; ...
      Apart from that, if there's still a problem, you would need to post a minimal demonstration -- a snippet like mine, including sufficient "real-world" data, that exhibits the problem, and perhaps some clarification as to how the actual output differs from the desired output.
        Hi,
        You are correct when you say you are assuming that I am extracting data into a file, and then working on it. I am perfectly happy to post the connection routines I am using plus the data and time stuff (for a log file)here but I think it may be a little cluttered if I do that, I will post it in the "Code Catacombs" so that it can be re-used if required.......
        Let see if I can get the "readmore" TAG to work....
        A1-400-EC-001A|A1-4000<br/> A1-400-EC-001B|A1-4000<br/> A1-400-EC-001C|A1-4000<br/> A1-400-EC-001D|A1-4000<br/> A1-400-EC-001E|A1-4000<br/> A1-400-EC-001F|A1-4000<br/> A1-400-EC-001G|A1-4000<br/> A1-400-EC-001H|A1-4000<br/> A1-400-EC-001J|A1-4000<br/> A1-400-EC-001K|A1-4000<br/> A1-400-EHC-001|A1-400-HC-001<br/> A1-400-EKF-001A|A1-400-KF-001A<br/> A1-400-EKF-001B|A1-400-KF-001B<br/> A1-400-EKF-001C|A1-400-KF-001C<br/> A1-400-EKF-001D|A1-400-KF-001D<br/> A1-400-EKF-001E|A1-400-KF-001E<br/> A1-400-EKF-001F|A1-400-KF-001F<br/> A1-400-EKF-001G|A1-400-KF-001G<br/> A1-400-EKF-001H|A1-400-KF-001H<br/> A1-400-EKF-001J|A1-400-KF-001J<br/> A1-400-EKF-001K|A1-400-KF-001K<br/> A1-400-EKF-001L|A1-400-KF-001L<br/> A1-400-EKF-001M|A1-400-KF-001M<br/> A1-400-EN-003A|A1-4000<br/> A1-400-EN-003B|A1-4000<br/> A1-400-EPA-001A|A1-400-PA-001A<br/> A1-400-EPA-001B|A1-400-PA-001B<br/> A1-400-EPA-001C|A1-400-PA-001C<br/> A1-400-EPA-001D|A1-400-PA-001D<br/> A1-400-EPA-002A|A1-400-PA-002A<br/> A1-400-EPA-002B|A1-400-PA-002B<br/> A1-400-EPB-001|A1-400-PB-001<br/> A1-400-EPB-002A|A1-400-PB-002A<br/> A1-400-EPB-002B|A1-400-PB-002B<br/> A1-400-HA-001|A1-4000<br/> A1-400-HC-001|A1-4000<br/> A1-400-HX-001A|A1-400-HC-001<br/> A1-400-HX-001B|A1-400-HC-001<br/> A1-400-HX-001C|A1-400-HC-001<br/> A1-400-HX-001D|A1-400-HC-001<br/> A1-400-HX-001E|A1-400-HC-001<br/> A1-400-HX-001F|A1-400-HC-001<br/> A1-400-HX-001G|A1-400-HC-001<br/> A1-400-HX-001H|A1-400-HC-001<br/> A1-400-HX-001J|A1-400-HC-001<br/> A1-400-HX-001K|A1-400-HC-001<br/> A1-400-KF-001A|A1-400-HC-001<br/> A1-400-KF-001B|A1-400-HC-001<br/> A1-400-KF-001C|A1-400-HC-001<br/> A1-400-KF-001D|A1-400-HC-001<br/> A1-400-KF-001E|A1-400-HC-001<br/> A1-400-KF-001F|A1-400-HC-001<br/> A1-400-KF-001G|A1-400-HC-001<br/> A1-400-KF-001H|A1-400-HC-001<br/> A1-400-KF-001J|A1-400-HC-001<br/> A1-400-KF-001K|A1-400-HC-001<br/> A1-400-PA-001A|A1-400-HC-001<br/> A1-400-PA-001B|A1-4000<br/> A1-400-PA-001C|A1-4000<br/> A1-400-PA-001D|A1-4000<br/> A1-400-PA-002A|A1-4000<br/> A1-400-PA-002B|A1-4000<br/> A1-400-PB-001|A1-4000<br/> A1-400-PB-002A|A1-4000<br/> A1-400-PB-002B|A1-4000<br/> A1-400-TA-001|A1-4000<br/> A1-400-VB-001|A1-4000<br/> A1-400-ZD-001|A1-400-TA-001<br/> A1-4000|A1<br/> A1-4000-AG-001-6-A21-WN|A1-4000<br/> A1-4000-CM-001-3-A21-BP|A1-4000<br/> A1-4000-CM-002-3-A21-BP|A1-4000<br/> A1-4000-CM-003-2-A21-BP|A1-4000<br/> A1-4000-CM-004-2-A21-BP|A1-4000<br/> A1-4000-CM-005-2-A21-BP|A1-4000<br/> A1-4000-CM-007-2-A21-BP|A1-4000<br/> A1-4000-CM-009-10-A21-HC|A1-4000<br/> A1-4000-CM-011-2-A21-BP|A1-4000<br/> A1-4000-CM-012-2-A21-BP|A1-4000<br/> A1-4000-CM-013-2-A21-BP|A1-4000<br/> A1-4000-CM-015-2-A05-BP|A1-4000<br/> A1-4000-CM-019-2-A21-BP|A1-4000<br/> A1-4000-CM-020-20-A21-BP|A1-4000<br/> A1-4000-CM-021-16-A21-BP|A1-4000<br/> A1-4000-CM-022-16-A21-BP|A1-4000<br/> A1-4000-CM-023-16-A21-BP|A1-4000<br/> A1-4000-CM-024-16-A21-BP|A1-4000<br/> A1-4000-CM-026-20-A21-HC|A1-4000<br/> A1-4000-CM-029-12-A21-HC|A1-4000<br/> A1-4000-CM-030-20-A21-BP|A1-4000<br/> A1-4000-CM-031-16-A21-BP|A1-4000<br/> A1-4000-CM-032-16-A21-BP|A1-4000<br/> A1-4000-CM-033-16-A21-BP|A1-4000<br/> A1-4000-CM-034-16-A21-BP|A1-4000<br/> A1-4000-CM-036-16-A21-HC|A1-4000<br/> A1-4000-CM-040-20-A21-HC|A1-4000<br/> A1-4000-CM-041-10-A21-HC|A1-4000<br/> A1-4000-CM-042-10-A21-HC|A1-4000<br/> A1-4000-CM-043-10-A21-HC|A1-4000<br/> A1-4000-CM-044-10-A21-HC|A1-4000<br/> A1-4000-CM-045-10-A21-HC|A1-4000<br/> A1-4000-CM-050-20-A21-HC|A1-4000<br/> A1-4000-CM-051-10-A21-HC|A1-4000<br/> A1-4000-CM-052-10-A21-HC|A1-4000<br/> A1-4000-CM-053-10-A21-HC|A1-4000<br/> A1-4000-CM-054-10-A21-HC|A1-4000<br/> A1-4000-CM-055-10-A21-HC|A1-4000<br/> A1-4000-CM-061-4-A21-HC|A1-4000<br/> A1-4000-CM-062-4-A21-HC|A1-4000<br/> A1-4000-CM-064-1-A21-HC|A1-4000<br/> A1-4000-CM-065-1-A21-PP|A1-4000<br/> A1-4000-CM-071-10-A21-BP|A1-4000<br/> A1-4000-CM-072-12-A21-BP|A1-4000<br/> A1-4000-CM-073-16-A21-HC|A1-4000<br/> A1-4000-CM-074-16-A21-HC|A1-4000<br/> A1-4000-CM-075-12-A21-HC|A1-4000<br/> A1-4000-CM-077-10-A21-HC|A1-4000<br/> A1-4000-CM-078-12-A21-BP|A1-4000<br/> A1-4000-DMC-2211-01|A1-4000<br/> A1-4000-FCV-703A|A1-4000-CM-071-10-A21-BP<br/> A1-4000-FCV-703B|A1-4000-CM-036-16-A21-HC<br/> A1-4000-FIC-703A|A1-4000-FCV-703A<br/> A1-4000-FIC-703B|A1-4000-FCV-703B<br/> A1-4000-FT-703|A1-4000-FCV-703A<br/> A1-4000-FY-703A|A1-4000-FCV-703A<br/> A1-4000-FY-703B|A1-4000-FCV-703B<br/> A1-4000-GY-001-3/4-A21-BP|A1-4000<br/> A1-4000-GY-002-1 1/2-A21-BP|A1-4000<br/> A1-4000-GY-003-2-A21-BP|A1-4000<br/> A1-4000-LA-703|A1-4000-LT-705<br/> A1-4000-LA-707|A1-4000-LT-707B<br/> A1-4000-LG-702|A1-400-VB-001<br/> A1-4000-LI-703|A1-4000-LT-703<br/> A1-4000-LI-705|A1-4000-LT-705<br/> A1-4000-LI-707A|A1-4000-LT-707A<br/> A1-4000-LI-707B|A1-4000-LT-707B<br/> A1-4000-LI-707C|A1-4000-LT-707C<br/> A1-4000-LIC-701|A1-4000-LT-701<br/> A1-4000-LT-701|A1-400-VB-001<br/> A1-4000-LT-703|A1-400-TA-001<br/> A1-4000-LT-705|A1-400-TA-001<br/> A1-4000-LT-707A|A1-400-VB-001<br/> A1-4000-LT-707B|A1-400-VB-001<br/> A1-4000-LT-707C|A1-400-VB-001<br/> A1-4000-PG-701A|A1-400-PA-001A<br/> A1-4000-PG-701B|A1-400-PA-001B<br/> A1-4000-PG-701C|A1-400-PA-001C<br/> A1-4000-PG-701D|A1-400-PA-001D<br/> A1-4000-PG-702A|A1-400-PA-002A<br/> <br/>
        This is the code (all of it) that I am using the run over the extracted data...
        #!/usr/bin/perl<br/> use strict;<br/> use warnings;<br/> <br/> my %node;<br/> my $folder = "P:\\Prod-Operations\\Maint-Eng\\Maintenance Projects\\IN +F\\DB\\IFDB\\TAGHIERARCHY\\PerlScripts";<br/> my $resultfile = "resultset.txt";<br/> my $interset01 = "interset01.txt";<br/> my $interset02 = "interset02.txt";<br/> <br/> open (DATA, "< $folder\\$resultfile") || die "could not open file: $!" +;<br/> while (<DATA>) {<br/> my ( $c, $p ) = split /\|/;<br/> if ( $c eq $p ) { # these are easy, so finish them first<br/> print;<br/> next;<br/> }<br/> <br/> if ( exists( $node{$c}{child_of} )) {<br/> warn "$.: bad record: $c is child of both $p and $node{$c}{chi +ld_of}\n";<br/> next;<br/> }<br/> $node{$c}{child_of} = $p;<br/> $node{$p}{parent_of}{$c} = undef;<br/> }<br/> <br/> # begin the sorted output by looping over values that do not have pare +nts:<br/> open (INT01,">$folder\\$interset01") or die "Can not open file $folder +\\$interset01 for writing, quitting\n";<br/> <br/> for my $parent ( grep {!exists( $node{$_}{child_of} ) } keys %node ) { +<br/> my $children = $node{$parent}{parent_of}; # ref to hash of child +values<br/> trace_down( $children, \%node );<br/> }<br/> <br/> sub trace_down<br/> {<br/> my ( $kids, $tree ) = @_;<br/> for my $kid ( keys %$kids ) {<br/> print INT01 "$kid|$$tree{$kid}{child_of}";<br/> # print "$kid|$$tree{$kid}{child_of}\n";<br/> if ( exists( $$tree{$kid}{parent_of} )) {<br/> trace_down( $$tree{$kid}{parent_of}, $tree );<br/> }<br/> }<br/> }<br/> <br/> <br/>
        Here is a sample from the result set....
        <readmore> title "Result set sample"><br/> A1-4708-TT-732A|A1-4708-LS-001-30-B40-HC<br/> A1-4708-PT-702|A1-4708-LS-001-30-B40-HC<br/> A1-4708-PSV-704B|A1-4708-LS-001-30-B40-HC<br/> A1-4708-RG-761|A1-4708-LS-001-30-B40-HC<br/> A1-4708-PT-711C|A1-4708-LS-001-30-B40-HC<br/> A1-4708-TT-732C|A1-4708-LS-001-30-B40-HC<br/> A1-4708-XV-700|A1-4708-LS-001-30-B40-HC<br/> A1-4708-TT-702|A1-4708-LS-001-30-B40-HC<br/> A1-4708-TT-732B|A1-4708-LS-001-30-B40-HC<br/> A1-4708-PSV-704C|A1-4708-LS-001-30-B40-HC<br/> A1-4708-PSV-704D|A1-4708-LS-001-30-B40-HC<br/> A1-4708-PSV-704A|A1-4708-LS-001-30-B40-HC<br/> A1-4708-PT-711B|A1-4708-LS-001-30-B40-HC<br/> A1-4708-PG-703|A1-4708-LS-001-30-B40-HC<br/> A1-4708-PT-711A|A1-4708-LS-001-30-B40-HC<br/> A1-690-EGF-012C|A1-690-GF-012C<br/> A1-4800-RG-808|A1-4800-FO-029-1-A21-HC<br/> A1-4800-RG-809|A1-4800-FO-029-1-A21-HC<br/> A1-4800-PSV-708|A1-4800-FO-029-1-A21-HC<br/> A1-6900-RF-769|A1-6900-HM-042-6-A21-HC<br/> A1-4707-RB-770|A1-4600-IA-200-2-A21-BP<br/> A1-6900-TIC-713|A1-6900-TE-713<br/> A1-4000-VSH-711F|A1-400-KF-001F<br/> A1-400-EKF-001F|A1-400-KF-001F<br/> A1-600-XX-004~FCV353|A1-600-XX-004<br/> A1-600-XX-004~F01|A1-600-XX-004<br/> A1-600-XX-004~F02|A1-600-XX-004<br/> A1-600-XX-004~KV311|A1-600-XX-004<br/> A1-600-XX-004~VAG_S01C|A1-600-XX-004<br/> A1-600-XX-004~F03|A1-600-XX-004<br/> A1-600-XX-004~VAG_S01D|A1-600-XX-004<br/> A1-600-XX-004~KY354|A1-600-XX-004<br/> A1-600-XX-004~VAG_S01B|A1-600-XX-004<br/> A1-600-XX-004~PCV353|A1-600-XX-004<br/> A1-600-XX-004~VAG03|A1-600-XX-004<br/> A1-600-XX-004~E02B|A1-600-XX-004<br/> A1-600-XX-004~FO356|A1-600-XX-004<br/> A1-6000-JC-701|A1-600-XX-004<br/> A1-600-XX-004~E02A|A1-600-XX-004<br/> A1-600-XX-004~E01|A1-600-XX-004<br/> A1-600-XX-004~KY355|A1-600-XX-004<br/> A1-600-XX-004~F04|A1-600-XX-004<br/> A1-6000-RB-750|A1-600-XX-004<br/> A1-600-XX-004~VAG02|A1-600-XX-004<br/> A1-600-XX-004~S01B|A1-600-XX-004<br/> A1-600-XX-004~CVNG354|A1-600-XX-004<br/> A1-600-XX-004~E03|A1-600-XX-004<br/> A1-600-XX-004~F01C|A1-600-XX-004<br/> A1-600-XX-004~R01|A1-600-XX-004<br/> A1-4708-PDT-003|A1-4708-HS-002-20-C40-HC<br/> A1-4708-PCV-766|A1-4708-HS-002-20-C40-HC<br/> A1-4800-RG-770|A1-4800-FO-043-2-A21-HC<br/> A1-4800-RC-751|A1-4800-FO-043-2-A21-HC<br/> A1-4600-USH-703A|A1-460-EKF-003A<br/> A1-4600-USL-703A|A1-460-EKF-003A<br/> A1-4600-UA-703A|A1-460-EKF-003A<br/> A1-4600-UL-703A|A1-460-EKF-003A<br/> A1-4600-UB-703A|A1-460-EKF-003A<br/> A1-470-MT-011~33VG-11|A1-470-MT-011~20VG-1<br/> A1-4707-RA-781|A1-470-HA-071A<br/> A1-4707-PSV-004|A1-470-HA-071A<br/> A1-4707-TG-005|A1-470-HA-071A<br/> A1-4707-RF-751|A1-470-HA-071A<br/> A1-945-EY-003B|A1-945-ET-003B<br/> A1-730-ST-020|A1-7300-FW-339-1-A21-BP<br/> A1-470-MT-031~PDSH158|A1-470-MT-031~PDI158<br/> A1-4200-PZI-703D|A1-4200-PZT-703D<br/> A1-690-EGF-041J|A1-690-GF-041J<br/> A1-6900-LALL-712|A1-6900-LSLL-712A<br/> A1-4702-EZSH-012|A1-4702-EDV-012<br/> A1-4702-EZSL-012|A1-4702-EDV-012<br/> A1-4702-EXY-012|A1-4702-EDV-012<br/> A1-4702-EPT-012|A1-4702-EDV-012<br/> A1-4200-RC-762|A1-4200-CD-484-2-B13-WN<br/> A1-470-MS-071~TAHH-749|A1-470-MS-071~TSHH-749<br/> A1-470-MT-021~AT-ID-2|A1-470-ZA-021<br/> A1-470-MT-021~96RH-1|A1-470-ZA-021<br/> A1-470-MT-021~AT-ID-4|A1-470-ZA-021<br/> A1-470-MT-021~AT-ID-1|A1-470-ZA-021<br/> A1-470-MT-021~AT-ID-3|A1-470-ZA-021<br/> A1-470-MT-021~96RH|A1-470-ZA-021<br/> A1-470-MT-021~AT-ID-6|A1-470-ZA-021<br/> A1-470-MT-021~AT-ID-5|A1-470-ZA-021<br/> A1-4200-RB-776|A1-4200-CD-461-2-B13-WN<br/> A1-4200-RA-771|A1-4200-CD-461-2-B13-WN<br/> A1-470-XY-026|A1-470-XX-021<br/> A1-470-MT-021~HV439|A1-470-XX-021<br/> A1-470-MT-021~HV409|A1-470-XX-021<br/> A1-470-MT-021~HV402|A1-470-XX-021<br/> A1-470-XY-020|A1-470-XX-021<br/> A1-470-MT-021~HV431|A1-470-XX-021<br/> A1-470-XY-021|A1-470-XX-021<br/> A1-470-MT-021|A1-470-XX-021<br/> A1-470-MT-021~HV451B|A1-470-XX-021<br/> A1-470-MT-021~HV440|A1-470-XX-021<br/> A1-470-EG-021|A1-470-XX-021<br/> A1-470-XY-024|A1-470-XX-021<br/> A1-470-MT-021~HV406|A1-470-XX-021<br/> A1-470-MT-021~HV434|A1-470-XX-021<br/> A1-470-MT-021~HV415|A1-470-XX-021<br/> A1-470-XY-023|A1-470-XX-021<br/> A1-470-MT-021~HV405|A1-470-XX-021<br/> A1-470-XY-022|A1-470-XX-021<br/> A1-470-MT-021~HV413|A1-470-XX-021<br/> A1-470-ES-021|A1-470-XX-021<br/> A1-470-MT-021~HV442|A1-470-XX-021<br/> A1-470-MT-021~HV424|A1-470-XX-021<br/> A1-470-MT-021~HV403|A1-470-XX-021<br/> A1-470-LN-021|A1-470-XX-021<br/> A1-470-MT-021~HV408|A1-470-XX-021<br/> A1-470-MT-021~HV423|A1-470-XX-021<br/> A1-470-MT-021~HV437|A1-470-XX-021<br/> A1-470-MT-021~HV451A|A1-470-XX-021<br/> A1-470-MT-021~HV435|A1-470-XX-021<br/> A1-470-MT-021~HV433|A1-470-XX-021<br/> A1-470-MT-021~HV438|A1-470-XX-021<br/> A1-470-MT-021~HV422|A1-470-XX-021<br/> A1-470-ET-021|A1-470-XX-021<br/> A1-470-MT-021~HV432|A1-470-XX-021<br/> A1-470-EE-021|A1-470-XX-021<br/> A1-470-EB-021|A1-470-XX-021<br/> A1-470-MT-021~HV436|A1-470-XX-021<br/> A1-470-MT-021~HV421|A1-470-XX-021<br/> A1-470-MT-021~HV404|A1-470-XX-021<br/> A1-470-EE-022|A1-470-XX-021<br/> A1-470-ZA-021|A1-470-XX-021<br/> A1-470-MT-021~HV441|A1-470-XX-021<br/> A1-470-MT-021~HV407|A1-470-XX-021<br/> A1-480-KF-013B|A1-480-HC-013<br/> A1-480-KF-013A|A1-480-HC-013<br/> A1-480-EHC-013|A1-480-HC-013<br/> A1-4200-PT-709|A1-4200-FG-312-10-B13-HC<br/> A1-4200-TT-709|A1-4200-FG-312-10-B13-HC<br/> A1-4200-FT-709|A1-4200-FG-312-10-B13-HC<br/> A1-4200-RB-767|A1-4200-FG-312-10-B13-HC<br/> A1-4200-RB-766|A1-4200-FG-312-10-B13-HC<br/> A1-4707-RA-753|A1-4707-AG-001-2-B40-PP<br/> A1-4707-RG-768|A1-4707-AG-001-2-B40-PP<br/> A1-470-MT-031~VCK3-2|A1-470-MT-031~PH2<br/> A1-470-MT-031~VR22|A1-470-MT-031~PH2<br/> A1-470-MT-031~88HQ-1|A1-470-MT-031~PH2<br/> A1-6900-RF-768|A1-6900-HM-032-6-A21-HC<br/> A1-4707-PCV-766|A1-4707-HS-002-20-C40-HC<br/> A1-4707-PDT-003|A1-4707-HS-002-20-C40-HC<br/> A1-4800-JF-701|A1-4800<br/> A1-4800-FO-064-2-A21-HC|A1-4800<br/> A1-4800-CM-514-6-A21-HC|A1-4800<br/> A1-4800-FO-038-3-A21-HC|A1-4800<br/> A1-480-ES-009|A1-4800<br/> A1-4800-AG-002-4-A21-WN|A1-4800<br/> <br/> <br/>
        I was hoping that the number "A1-4100|A1" would be fairly close to the top of the "sorted" list as "A1-4100" is the parent for a ton of numbers, however, it appears at line 1705 (not show as I think I have probably killed the web site already with the data I have posted !!!)
        regards
        Nigel