Sorry for the delayed reply on this... I've been busy, but I've been using spare gray cells to consider your situation. :)
Given the rules you have provided and implied, a solution would seem to be fairly simple and straightforward. Indeed, overthinking the issue is a distinct danger to be avoided. The one big reservation I have is that, though you have implied it, you have never explicitly stated that each number is unique to only one chain. That is to say, something like this could never happen:
123-234-339-456-567
117-234-339
131
213-339-456
372
In the sample above, I have altered the numbers so that 234, 339, and 456 each appear in at least two chains. Your data sample, which shows only a number and its predecessor in the chain, cannot adequately represent the data in this altered environment, since there now exist multiple paths in the data for determining the first number in the chain. For instance, the first number of the chain ending in 567 is now indistinguishable; using the data as it's formatted, the first number could be 123, 117, or 213 -- although, of course, the only correct answer is 123.
The reasonable assumption, then, must be to accept and rely on your implicit rule: each three-digit number can only appear in one chain.
From there, the solution is fairly easy. Since your original question did not involve how to pull in your data, I'm going to simplify my sample code by starting with the data already formatted in a way that Perl understands. I am also going to stick with built-in Perl functions, and not require any extra modules.
#!/usr/bin/perl -w
use strict;
my @data = ( [ 567, 456 ],
[ 456, 345 ],
[ 345, 234 ],
[ 234, 123 ],
[ 339, 228 ],
[ 228, 117 ],
[ 131, undef ],
[ 435, 324 ],
[ 324, 213 ],
[ 372, undef ]
);
sub replace {
my ( $num_first_ref, $pred_num_ref, $num, $pred ) = @_;
# Catch the first number in the chain
$num_first_ref->{ $pred } = $pred;
# Assign current $pred as possible first
$num_first_ref->{ $num } = $pred;
# Use reverse hash to look up later/higher numbers and update
if ( exists( $pred_num_ref->{ $num } ) && ( my $higher_num = $pred
+_num_ref->{ $num } ) ) {
# Reassign current $pred as possible first
$num_first_ref->{ $higher_num } = $pred;
replace( $num_first_ref, $pred_num_ref, $higher_num, $pred );
}
}
my %num_first; # Calculated data for output goes here
my %pred_num; # 'Reverse' hash for recursive lookup
for my $nums ( @data ) {
# Handle single values
unless ( defined( $nums->[ 1 ] ) ) {
$num_first{ $nums->[ 0 ] } = $nums->[ 0 ];
next;
}
# Load reverse hash with predecessor as key
$pred_num{ $nums->[ 1 ] } = $nums->[ 0 ];
replace( \%num_first, \%pred_num, $nums->[ 0 ], $nums->[ 1 ] );
}
for my $high_num ( sort { $a <=> $b } keys %num_first ) {
print "$high_num => $num_first{ $high_num }\n";
}
Output:
117 => 117
123 => 123
131 => 131
213 => 213
228 => 117
234 => 123
324 => 213
339 => 117
345 => 123
372 => 372
435 => 213
456 => 123
567 => 123
This uses a reverse hash,
%pred_num, and a recursive subroutine,
replace, to keep track of later chain numbers that have already been seen, and update them to the current possible first number. It doesn't matter how many data rows you have, or how long the chains are, this will handle any amount of data you throw at it -- as long as the data follows the rules. Boilerplate code for handling rule exceptions can always be added as desired.
Posts are HTML formatted. Put <p> </p> tags around your paragraphs. Put <code> </code> tags around your code and data!
Titles consisting of a single word are discouraged, and in most cases are disallowed outright.
Read Where should I post X? if you're not absolutely sure you're posting in the right place.
Please read these before you post! —
Posts may use any of the Perl Monks Approved HTML tags:
- a, abbr, b, big, blockquote, br, caption, center, col, colgroup, dd, del, details, div, dl, dt, em, font, h1, h2, h3, h4, h5, h6, hr, i, ins, li, ol, p, pre, readmore, small, span, spoiler, strike, strong, sub, summary, sup, table, tbody, td, tfoot, th, thead, tr, tt, u, ul, wbr
You may need to use entities for some characters, as follows. (Exception: Within code tags, you can put the characters literally.)
| |
For: |
|
Use: |
| & | | & |
| < | | < |
| > | | > |
| [ | | [ |
| ] | | ] |
Link using PerlMonks shortcuts! What shortcuts can I use for linking?
See Writeup Formatting Tips and other pages linked from there for more info.