我有一个时间跨度列表(以整数元组的形式给出),例如:
timespans = [ (1200, 1210)
, (1202, 1209)
, (1505, 1900)
, (1300, 1500)
, (1400, 1430)
]
我想找到一个优雅的Haskell解决方案来确定列表中的时间跨度未涵盖的时间间隔。
答案 0 :(得分:4)
首先,我会按照他们的开始时间排序。然后,您可以非常轻松地合并重叠跨度。一旦你有了它,你可以通过成对地迭代合并的跨度来找到间隙(通过用它的尾部拉链)。差距将是从第一项的结束时间到第二项的开始时间的跨度。
在代码中,这将是这样的:
mergeSortedSpans [] = []
mergeSortedSpans ((from1, to1):(from2, to2):spans) | to1 >= from2 =
mergeSortedSpans $ (from1, max to1 to2):spans
mergeSortedSpans (span:spans) = span : mergeSortedSpans spans
inPairs _ [] = []
inPairs f (x:xs) = zipWith f (x:xs) xs
gap (_, to1) (from2, _) = (to1, from2)
gaps = inPairs gap . mergeSortedSpans . sort
用法:
gaps timespans
-- [(100,500),(1210,1300),(1500,1505)]
答案 1 :(得分:3)
我的解决方案使用分而治之的方法来融合所有重叠的时间跨度,以获得非重叠时间跨度的排序列表:
module Test
where
type Time = Int
type Start = Time
type Stop = Time
type Span = (Start, Stop)
timespans :: [Span]
timespans = [ (1200, 1210)
, (1202, 1209)
, (1505, 1900)
, (1300, 1500)
, (1400, 1430)
, (500,1200)
, (20,100)
]
flattentime :: [Span] -> [Span]
flattentime [] = []
flattentime [x] = [x]
flattentime (s:ss) = combine (flattentime [ times | times <- ss, (fst times) < (fst s) ]) s
(flattentime [ times | times <- ss, (fst times) >= (fst s) ])
combine [] s [] = [s]
combine [] s ss2 = melt s (head ss2) ++ tail ss2
combine ss1 s [] = firsts ss1 ++ melt (last ss1) s
combine ss1 s ss2 = (firsts ss1) ++ melt3 (last ss1) s (head ss2) ++ (tail ss2)
melt (x1,x2) (x3,x4) | x2 < x3 = [(x1,x2), (x3,x4)]
| x4 < x2 = [(x1,x2)]
| otherwise = [(x1,x4)]
melt3 (x1,x2) (x3,x4) (x5,x6) = if (length ss >1) then (head ss):(melt y (x5,x6)) else melt y (x5,x6)
where ss = melt (x1,x2) (x3,x4)
y = last ss
firsts [x] = []
firsts [] = []
firsts (x:xs) = x:(firsts xs)
它不是那么干净和优雅,我希望它会......任何人都有一个更短的解决方案吗?
答案 2 :(得分:3)
优雅 - 你的意思是什么?
import Data.List
timespans = [ (1200, 1210)
, (1202, 1209)
, (1505, 1900)
, (1300, 1500)
, (1400, 1430)
]
gaps xs0 = filter g $ zipWith f xs (tail xs) where
xs = merge $ sort xs0
f (_, t0) (t1, _) = (t0, t1)
g (t0, t1) = t0 < t1
merge [] = []
merge ((t0, t1):(t2, t3):ys) | t2 < t1 = merge ((t0, max t1 t3) : ys)
merge (y:ys) = y : merge ys
main = print (gaps timespans)
答案 3 :(得分:2)
谢谢sepp2k - 你的权利;你建议的方式更容易!在使用Haskell-Code:
flattentime :: [(Integer,Integer)] -> [(Integer,Integer)]
flattentime [] = []
flattentime [x] = [x]
flattentime ((x1,x2):(y1,y2):ts) | y2<x2 = (x1,x2):(flattentime ts)
| y1<x2 = (x1,y2):(flattentime ts)
| otherwise = (x1,x2) : (flattentime ((y1,y2):ts))
然后我只需要打电话:
> (flattentime.sort) timespans