Решение на Haskell, потому что я плохо знаю синтаксис F #, но его должно быть достаточно легко перевести:
type TimeStamp = Integer -- ticks
type TimeSpan = Integer -- difference between TimeStamps
groupContiguousDataPoints :: TimeSpan -> [(TimeStamp, a)] -> [[(TimeStamp, a)]]
В прелюдии есть функция groupBy :: (a -> a -> Bool) -> [a] -> [[a]]
:
Функция группы берет список и возвращает список списков так, что конкатенация результата равна аргументу. Более того, каждый подсписок в результате содержит только равные элементы. Например,
group "Mississippi" = ["M","i","ss","i","ss","i","pp","i"]
Это особый случай groupBy, который позволяет программисту предоставлять собственный тест на равенство.
Это не совсем то, что мы хотим, потому что он сравнивает каждый элемент в списке с первым элементом текущей группы, и нам нужно сравнить последовательные элементы. Если бы у нас была такая функция groupBy1
, мы могли бы легко написать groupContiguousDataPoints
:
groupContiguousDataPoints maxTimeDiff list = groupBy1 (\(t1, _) (t2, _) -> t2 - t1 <= maxTimeDiff) list
Итак, давайте напишем это!
groupBy1 :: (a -> a -> Bool) -> [a] -> [[a]]
groupBy1 _ [] = [[]]
groupBy1 _ [x] = [[x]]
groupBy1 comp (x : xs@(y : _))
| comp x y = (x : firstGroup) : otherGroups
| otherwise = [x] : groups
where groups@(firstGroup : otherGroups) = groupBy1 comp xs
ОБНОВЛЕНИЕ: похоже, что F # не позволяет вам сопоставлять паттерны на seq
, поэтому перевод не так уж и прост. Тем не менее, этот поток в HubFS показывает способ последовательности шаблонных совпадений путем преобразования их в LazyList
при необходимости.
UPDATE2: списки на Haskell являются ленивыми и генерируются по мере необходимости, поэтому они соответствуют F # * LazyList
(а не seq
, потому что сгенерированные данные кэшируются (и сборщик мусора, конечно, если вы больше не держите ссылку на него)).