実際、ハッシュベースのアプローチがこの問題に適しているとは思いません。リスト処理の問題としてアプローチすることをお勧めします。Haskell でのアプローチについて説明します (コードを少し追加するだけで Perl に変換できます)。
一般的なアプローチは、任意の時点で重なり合っている要素の数を集計し続けることです。これを行うには、(開始、終了) ペアとしての要素の引数リストから、「デルタ」のリスト (実行中の合計の変化) を作成します。次に、これらのデルタを発生する場所で並べ替え、同時に発生するものを結合します。最後に、デルタの実行中の合計を保持します。これは、各期間の開始時に重複する要素の数に等しくなります (各期間は次の開始時に終了します)。
完全なコード:
import Data.List -- sortBy
import Data.Ord -- comparing
import Data.Function -- `on`
withDelta delta x = (x, delta)
episodeToDelta elements = increases ++ decreases
where increases = map (withDelta 1 . fst) elements
decreases = map (withDelta (-1) . snd) elements
compactDelta::[(Integer,Integer)]->(Integer,Integer)
compactDelta (x:xs) = ((fst x),(sum $ map snd (x:xs)))
adjustTotal (t, delta) ((t1, total1):rest) = (t, total1 + delta):(t1,total1):rest
deltasToRunningTotal = reverse . foldr adjustTotal [(0,0)] . reverse
noZeros = filter (\(_, d) -> d /= 0)
elementsToRunningTotal = deltasToRunningTotal . noZeros . map compactDelta . groupBy ((==) `on` fst) . sortBy (comparing fst) . elementToDelta
sample_elements = [(10,15),(5,9),(13,22),(15,19),(14,16),(3,8),(2,12),(20,22),(23,29)]
> sortBy (comparing fst) sample_elements
[(2,12),(3,8),(5,9),(10,15),(13,22),(14,16),(15,19),(20,22),(23,29)]
> episodesToRunningTotal sample_elements
[(0,0),(2,1),(3,2),(5,3),(8,2),(9,1),(10,2),(12,1),(13,2),(14,3),(16,2),(19,1),(20,2),(22,0),(23,1),(29,0)]