I tried your code and it would not work as taken from the email. I used -w and got a large number of entries. Cleaned a few things up, but within @encoded element 0 was always undefined(used Data::Dumper. So I changed push @encoded, [$item[0], START, $counter]; to push @encoded, [$item->[0], START, $counter];
This cleared up the data. I am still getting a warning on $current only used once. Thought I would stop at that point. Also did not like END, so make START/END as STARTA/ENDA so Perl wouldn't complain about END being a keyword. Wags ;) -----Original Message----- From: Jonathan E. Paton [mailto:[EMAIL PROTECTED]] Sent: Thursday, May 30, 2002 14:08 To: [EMAIL PROTECTED] Subject: Re: union of times algorithm > I'm trying to come up with an algorithm that seems like it ought to be > really easy, but it's turning out to be pretty tough... > > Basically I have three pairs of start/stop times, e.g.: > > 3, 5 > 4, 10 > 15, 20 > > I want the total time covered by all these ranges. I can't just say (5-3 + > 10-4 + 20-15) because the 3,5 and 4,10 ranges overlap. The desired answer > for this case is 13, 3 to 10 and 15 to 20. I have the start times in two > arrays, @starts and @stops. > > I have to do this probably a million+ times. Any ideas on how I could go > about this? Oh... a million? Better be a fast ALGORITHM: use constant START => 0; use constant END => 1; my @timeslices = ( [4, 9], [3, 6], [2, 4] ); # Turns the above into: # [4, START, 1] # [9, END, 1] # [3, START, 2] # [6, END, 2] # [2, START, 3] # [4, END, 3] my ($counter, @encoded) = 1; foreach my $item (@timeslices) { push @encoded, [$item[0], START, $counter]; push @encoded, [$item[1], END, $counter++]; } # Turns @encoded above into: # [2, START, 3] # [3, START, 2] # [4, START, 1] # [4, END, 3] # [6, END, 2] # [9, END, 1] my @sorted = map { $_->[0] } sort { $a->[0] <=> $b->[0] # Sort by element 0 || $b->[1] <=> $b->[1] # then by element 1 } @encoded; # Keep track of beginning time and total my $total = 0; my $previous = 0; my %active; # Active timeslots # Loop: # * If we get a START, add it to a hash # * If we get an END, remove it from the hash # * If the hash has something in it, then # total += previous - current # foreach my $item (@sorted) { # * If we get a START, add it to a hash if ($item[0] == START) { $active{$item[2]}++; } # * If we get an END, remove it from the hash else { delete $active{$item[2]}; } # * If the hash has something in it, then # total += previous - current if (%active != 0) { $total += $previous - $current; } } print $total; =================================================== There is a bug someplace that prevents it printing the correct value - knowledgable people are welcome to find it... I've no more time available just now. I think this might be the fastest solution thus far. Jonathan Paton ===== $_=q|.,&@$$. ,.@$&@$. .&$$@. ,,$ ....!$_=$p.'&$@.',y'&$@' .,';for(/\S+/g){ !|.q| .$ .,@, ,$, .,.. @, ,$ ,,@ .,,.!++$.<22?${'y'.$_}=chr$.+64:[$$=${'y' !|.q| ,@$@&.,. $$$&, ..@&&$,,, $., ..!.$_},$y.=($.=~/22\|26\|3(3\|7)/x?' ' !|.q|. @ ., ,.&,,, , .$..&. .,$ .,,!.$$:"\l$$")]};$y=~/ (.*)/;warn"$1\n" !|.q|. $ .,. .,$$&&$...&., @.,.&@$@ .|,map{-$|--?$r:$p.=$_}split'!';eval$r __________________________________________________ Do You Yahoo!? Everything you'll ever need on one web page from News and Sport to Email and Music Charts http://uk.my.yahoo.com -- To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED] -- To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]