-----------------------------------------------------------------------------

-- |

-- Module      :  Data.Series

-- Copyright   :  (c) Laurent P. René de Cotret

-- License     :  MIT

-- Maintainer  :  laurent.decotret@outlook.com

-- Portability :  portable

--

-- This module contains data structures and functions to work with 'Series' capable of holding any Haskell value. 

-- For better performance, at the cost of less flexibility, see the "Data.Series.Unboxed".

--

-- = Introduction to series

--

-- A 'Series' of type @Series k a@ is a labeled array of values of type @a@,

-- indexed by keys of type @k@.

--

-- Like `Data.Map.Strict.Map` from the @containers@ package, 'Series' support efficient:

--

--      * random access by key ( \(O(\log n)\) );

--      * slice by key ( \(O(\log n)\) ).

--

-- Like `Data.Vector.Vector`, they support efficient:

--

--      * random access by index ( \(O(1)\) );

--      * slice by index ( \(O(1)\) );

--      * numerical operations.

--

-- This module re-exports most of the content of "Data.Series.Generic", with type signatures 

-- specialized to the boxed container type `Data.Vector.Vector`.

--

-- For better performance (at the cost of more constraints), especially when it comes to numerical calculations, prefer to

-- use "Data.Series.Unboxed", which contains an implementation of series specialized to the unboxed container type `Data.Vector.Unboxed.Vector`.

 
module Data.Series (
    Series, index, values,

    -- * Building/converting 'Series'

    singleton, fromIndex,
    -- ** Lists

    fromList, toList,
    -- ** Vectors

    fromVector, toVector,
    -- ** Handling duplicates

    Occurrence, fromListDuplicates, fromVectorDuplicates,
    -- ** Strict Maps

    fromStrictMap, toStrictMap,
    -- ** Lazy Maps

    fromLazyMap, toLazyMap,
    -- ** Ad-hoc conversion with other data structures

    IsSeries(..),
    -- ** Conversion between 'Series' types

    G.convert,

    -- * Mapping and filtering

    map, mapWithKey, mapIndex, concatMap,
    take, takeWhile, drop, dropWhile, filter, filterWithKey,
    -- ** Mapping with effects

    mapWithKeyM, mapWithKeyM_, forWithKeyM, forWithKeyM_, traverseWithKey,

    -- * Combining series

    zipWith, zipWithMatched, zipWithKey,
    zipWith3, zipWithMatched3, zipWithKey3,
    ZipStrategy, skipStrategy, mapStrategy, constStrategy, zipWithStrategy, zipWithStrategy3,
    zipWithMonoid, esum, eproduct, unzip, unzip3,

    -- * Index manipulation

    require, catMaybes, dropIndex,

    -- * Accessors

    -- ** Bulk access

    select, selectWhere, Range, to, from, upto, Selection, 
    -- ** Single-element access

    at, iat,

    -- * Replacing values

    replace, (|->), (<-|),

    -- * Scans

    forwardFill,

    -- * Grouping and windowing operations

    groupBy, Grouping, aggregateWith, foldWith, 
    windowing, expanding,

    -- * Folds

    fold, foldM, foldWithKey, foldMWithKey, foldMapWithKey,
    -- ** Specialized folds

    G.mean, G.variance, G.std,
    length, null, all, any, and, or, sum, product, maximum, maximumOn, minimum, minimumOn, 
    argmin, argmax,

    -- * Scans

    postscanl, prescanl,

    -- * Displaying 'Series'

    display, displayWith,
    noLongerThan,
    DisplayOptions(..), G.defaultDisplayOptions
) where

import           Control.Foldl       ( Fold, FoldM )
import qualified Data.Map.Lazy       as ML
import qualified Data.Map.Strict     as MS
import           Data.Series.Index   ( Index )
import           Data.Series.Generic ( IsSeries(..), Range, Selection, ZipStrategy, Occurrence, DisplayOptions(..)
                                     , to, from, upto, skipStrategy, mapStrategy, constStrategy, noLongerThan
                                     )
import qualified Data.Series.Generic as G
import           Data.Vector         ( Vector )

import           Prelude             hiding ( map, concatMap, zipWith, zipWith3, filter, take, takeWhile, drop, dropWhile, last, unzip, unzip3
                                            , length, null, all, any, and, or, sum, product, maximum, minimum, 
                                            )

-- $setup

-- >>> import qualified Data.Series as Series

-- >>> import qualified Data.Series.Index as Index


infixl 1 `select` 
infix 6 |->, <-|

-- | A series is a labeled array of values of type @a@,

-- indexed by keys of type @k@.

--

-- Like @Data.Map@ and @Data.HashMap@, they support efficient:

--

--      * random access by key ( \(O(\log n)\) );

--      * slice by key ( \(O(\log n)\) ).

--

-- Like @Data.Vector.Vector@, they support efficient:

--

--      * random access by index ( \(O(1)\) );

--      * slice by index ( \(O(1)\) );

--      * numerical operations.

type Series = G.Series Vector


index :: Series k a -> Index k
{-# INLINABLE index #-}
index :: forall k a. Series k a -> Index k
index = Series Vector k a -> Index k
forall {k1} (v :: k1 -> *) k2 (a :: k1). Series v k2 a -> Index k2
G.index


values :: Series k a -> Vector a
{-# INLINABLE values #-}
values :: forall k a. Series k a -> Vector a
values = Series Vector k a -> Vector a
forall {k1} (v :: k1 -> *) k2 (a :: k1). Series v k2 a -> v a
G.values


-- | Create a 'Series' with a single element.

singleton :: k -> a -> Series k a
{-# INLINABLE singleton #-}
singleton :: forall k a. k -> a -> Series k a
singleton = k -> a -> Series Vector k a
forall (v :: * -> *) a k. Vector v a => k -> a -> Series v k a
G.singleton


-- | \(O(n)\) Generate a 'Series' by mapping every element of its index.

--

-- >>> fromIndex (const (0::Int)) $ Index.fromList ['a','b','c','d']

-- index | values

-- ----- | ------

--   'a' |      0

--   'b' |      0

--   'c' |      0

--   'd' |      0

fromIndex :: (k -> a) -> Index k -> Series k a
{-# INLINABLE fromIndex #-}
fromIndex :: forall k a. (k -> a) -> Index k -> Series k a
fromIndex = (k -> a) -> Index k -> Series Vector k a
forall (v :: * -> *) a k.
Vector v a =>
(k -> a) -> Index k -> Series v k a
G.fromIndex


-- | Construct a series from a list of key-value pairs. There is no

-- condition on the order of pairs.

--

-- >>> let xs = fromList [('b', 0::Int), ('a', 5), ('d', 1) ]

-- >>> xs

-- index | values

-- ----- | ------

--   'a' |      5

--   'b' |      0

--   'd' |      1

--

-- If you need to handle duplicate keys, take a look at `fromListDuplicates`.

fromList :: Ord k => [(k, a)] -> Series k a
{-# INLINABLE fromList #-}
fromList :: forall k a. Ord k => [(k, a)] -> Series k a
fromList = [(k, a)] -> Series Vector k a
forall (v :: * -> *) a k.
(Vector v a, Ord k) =>
[(k, a)] -> Series v k a
G.fromList


-- | Construct a series from a list of key-value pairs.

-- Contrary to `fromList`, values at duplicate keys are preserved. To keep each

-- key unique, an `Occurrence` number counts up.

--

-- >>> let xs = fromListDuplicates [('b', 0::Int), ('a', 5), ('d', 1), ('d', -4), ('d', 7) ]

-- >>> xs

--   index | values

--   ----- | ------

-- ('a',0) |      5

-- ('b',0) |      0

-- ('d',0) |      1

-- ('d',1) |     -4

-- ('d',2) |      7

fromListDuplicates :: Ord k => [(k, a)] -> Series (k, Occurrence) a
{-# INLINABLE fromListDuplicates #-}
fromListDuplicates :: forall k a. Ord k => [(k, a)] -> Series (k, Occurrence) a
fromListDuplicates = [(k, a)] -> Series Vector (k, Occurrence) a
forall (v :: * -> *) a k.
(Vector v a, Ord k) =>
[(k, a)] -> Series v (k, Occurrence) a
G.fromListDuplicates


-- | Construct a list from key-value pairs. The elements are in order sorted by key:

--

-- >>> let xs = Series.fromList [ ('b', 0::Int), ('a', 5), ('d', 1) ]

-- >>> xs

-- index | values

-- ----- | ------

--   'a' |      5

--   'b' |      0

--   'd' |      1

-- >>> toList xs

-- [('a',5),('b',0),('d',1)]

toList :: Series k a -> [(k, a)]
{-# INLINABLE toList #-}
toList :: forall k a. Series k a -> [(k, a)]
toList = Series Vector k a -> [(k, a)]
forall (v :: * -> *) a k. Vector v a => Series v k a -> [(k, a)]
G.toList


-- | Construct a 'Vector' of key-value pairs. The elements are in order sorted by key. 

toVector :: Series k a -> Vector (k, a)
{-# INLINABLE toVector #-}
toVector :: forall k a. Series k a -> Vector (k, a)
toVector = Series Vector k a -> Vector (k, a)
forall (v :: * -> *) a k.
(Vector v a, Vector v k, Vector v (k, a)) =>
Series v k a -> v (k, a)
G.toVector


-- | Construct a 'Series' from a 'Vector' of key-value pairs. There is no

-- condition on the order of pairs. Duplicate keys are silently dropped. If you

-- need to handle duplicate keys, see 'fromVectorDuplicates'.

--

-- Note that due to differences in sorting,

-- @'Series.fromList'@ and @'Series.fromVector' . 'Vector.fromList'@ 

-- may not be equivalent if the input list contains duplicate keys.

fromVector :: Ord k => Vector (k, a) -> Series k a
{-# INLINABLE fromVector #-}
fromVector :: forall k a. Ord k => Vector (k, a) -> Series k a
fromVector = Vector (k, a) -> Series Vector k a
forall k (v :: * -> *) a.
(Ord k, Vector v k, Vector v a, Vector v (k, a)) =>
v (k, a) -> Series v k a
G.fromVector


-- | Construct a series from a 'Vector' of key-value pairs.

-- Contrary to 'fromVector', values at duplicate keys are preserved. To keep each

-- key unique, an 'Occurrence' number counts up.

--

-- >>> import qualified Data.Vector as Vector

-- >>> let xs = fromVectorDuplicates $ Vector.fromList [('b', 0::Int), ('a', 5), ('d', 1), ('d', -4), ('d', 7) ]

-- >>> xs

--   index | values

--   ----- | ------

-- ('a',0) |      5

-- ('b',0) |      0

-- ('d',0) |      1

-- ('d',1) |     -4

-- ('d',2) |      7

fromVectorDuplicates :: Ord k => Vector (k, a) -> Series (k, Occurrence) a
{-# INLINABLE fromVectorDuplicates #-}
fromVectorDuplicates :: forall k a. Ord k => Vector (k, a) -> Series (k, Occurrence) a
fromVectorDuplicates = Vector (k, a) -> Series Vector (k, Occurrence) a
forall k (v :: * -> *) a.
(Ord k, Vector v k, Vector v a, Vector v (k, a),
 Vector v (k, Occurrence)) =>
v (k, a) -> Series v (k, Occurrence) a
G.fromVectorDuplicates


-- | Convert a series into a lazy @Map@.

toLazyMap :: Series k a -> ML.Map k a
{-# INLINABLE toLazyMap #-}
toLazyMap :: forall k a. Series k a -> Map k a
toLazyMap = Series Vector k a -> Map k a
forall (v :: * -> *) a k. Vector v a => Series v k a -> Map k a
G.toLazyMap


-- | Construct a series from a lazy @Map@.

fromLazyMap :: ML.Map k a -> Series k a
{-# INLINABLE fromLazyMap #-}
fromLazyMap :: forall k a. Map k a -> Series k a
fromLazyMap = Map k a -> Series Vector k a
forall (v :: * -> *) a k. Vector v a => Map k a -> Series v k a
G.fromLazyMap


-- | Convert a series into a strict @Map@.

toStrictMap :: Series k a -> MS.Map k a
{-# INLINABLE toStrictMap #-}
toStrictMap :: forall k a. Series k a -> Map k a
toStrictMap = Series Vector k a -> Map k a
forall (v :: * -> *) a k. Vector v a => Series v k a -> Map k a
G.toStrictMap


-- | Construct a series from a strict @Map@.

fromStrictMap :: MS.Map k a -> Series k a
{-# INLINABLE fromStrictMap #-}
fromStrictMap :: forall k a. Map k a -> Series k a
fromStrictMap = Map k a -> Series Vector k a
forall (v :: * -> *) a k. Vector v a => Map k a -> Series v k a
G.fromStrictMap


-- | \(O(n)\) Map every element of a 'Series'.

map :: (a -> b) -> Series k a -> Series k b
{-# INLINABLE map #-}
map :: forall a b k. (a -> b) -> Series k a -> Series k b
map = (a -> b) -> Series Vector k a -> Series Vector k b
forall (v :: * -> *) a b k.
(Vector v a, Vector v b) =>
(a -> b) -> Series v k a -> Series v k b
G.map


-- | \(O(n)\) Map every element of a 'Series', possibly using the key as well.

mapWithKey :: (k -> a -> b) -> Series k a -> Series k b
{-# INLINABLE mapWithKey #-}
mapWithKey :: forall k a b. (k -> a -> b) -> Series k a -> Series k b
mapWithKey = (k -> a -> b) -> Series Vector k a -> Series Vector k b
forall (v :: * -> *) a b k.
(Vector v a, Vector v b) =>
(k -> a -> b) -> Series v k a -> Series v k b
G.mapWithKey


-- | \(O(n \log n)\).

-- Map each key in the index to another value. Note that the resulting series

-- may have less elements, because each key must be unique.

--

-- In case new keys are conflicting, the first element is kept.

--

-- >>> let xs = Series.fromList [("Paris", 1 :: Int), ("London", 2), ("Lisbon", 4)]

-- >>> xs

--    index | values

--    ----- | ------

-- "Lisbon" |      4

-- "London" |      2

--  "Paris" |      1

-- >>> import qualified Data.List

-- >>> xs `mapIndex` (Data.List.take 1)

-- index | values

-- ----- | ------

--   "L" |      4

--   "P" |      1

mapIndex :: (Ord k, Ord g) => Series k a -> (k -> g) -> Series g a
{-# INLINABLE mapIndex #-}
mapIndex :: forall k g a.
(Ord k, Ord g) =>
Series k a -> (k -> g) -> Series g a
mapIndex = Series Vector k a -> (k -> g) -> Series Vector g a
forall (v :: * -> *) a k g.
(Vector v a, Ord k, Ord g) =>
Series v k a -> (k -> g) -> Series v g a
G.mapIndex


-- | Map a function over all the elements of a 'Series' and concatenate the result into a single 'Series'.

concatMap :: Ord k 
          => (a -> Series k b) 
          -> Series k a 
          -> Series k b
{-# INLINABLE concatMap #-}
concatMap :: forall k a b.
Ord k =>
(a -> Series k b) -> Series k a -> Series k b
concatMap = (a -> Series Vector k b) -> Series Vector k a -> Series Vector k b
forall (v :: * -> *) a k b.
(Vector v a, Vector v k, Vector v b, Vector v (k, a),
 Vector v (k, b), Ord k) =>
(a -> Series v k b) -> Series v k a -> Series v k b
G.concatMap


-- | \(O(n)\) Apply the monadic action to every element of a series and its

-- index, yielding a series of results.

mapWithKeyM :: (Monad m, Ord k) => (k -> a -> m b) -> Series k a -> m (Series k b)
{-# INLINABLE mapWithKeyM #-}
mapWithKeyM :: forall (m :: * -> *) k a b.
(Monad m, Ord k) =>
(k -> a -> m b) -> Series k a -> m (Series k b)
mapWithKeyM = (k -> a -> m b) -> Series Vector k a -> m (Series Vector k b)
forall (v :: * -> *) a b (m :: * -> *) k.
(Vector v a, Vector v b, Monad m, Ord k) =>
(k -> a -> m b) -> Series v k a -> m (Series v k b)
G.mapWithKeyM


-- | \(O(n)\) Apply the monadic action to every element of a series and its

-- index, discarding the results.

mapWithKeyM_ :: Monad m => (k -> a -> m b) -> Series k a -> m ()
{-# INLINABLE mapWithKeyM_ #-}
mapWithKeyM_ :: forall (m :: * -> *) k a b.
Monad m =>
(k -> a -> m b) -> Series k a -> m ()
mapWithKeyM_ = (k -> a -> m b) -> Series Vector k a -> m ()
forall (v :: * -> *) a (m :: * -> *) k b.
(Vector v a, Monad m) =>
(k -> a -> m b) -> Series v k a -> m ()
G.mapWithKeyM_


-- | \(O(n)\) Apply the monadic action to all elements of the series and their associated keys, 

-- yielding a series of results.

forWithKeyM :: (Monad m, Ord k) => Series k a -> (k -> a -> m b) -> m (Series k b)
{-# INLINABLE forWithKeyM #-}
forWithKeyM :: forall (m :: * -> *) k a b.
(Monad m, Ord k) =>
Series k a -> (k -> a -> m b) -> m (Series k b)
forWithKeyM = Series Vector k a -> (k -> a -> m b) -> m (Series Vector k b)
forall (v :: * -> *) a b (m :: * -> *) k.
(Vector v a, Vector v b, Monad m, Ord k) =>
Series v k a -> (k -> a -> m b) -> m (Series v k b)
G.forWithKeyM


-- | \(O(n)\) Apply the monadic action to all elements of the series and their associated keys, 

-- discarding the results.

forWithKeyM_ :: Monad m => Series k a -> (k -> a -> m b) -> m ()
{-# INLINABLE forWithKeyM_ #-}
forWithKeyM_ :: forall (m :: * -> *) k a b.
Monad m =>
Series k a -> (k -> a -> m b) -> m ()
forWithKeyM_ = Series Vector k a -> (k -> a -> m b) -> m ()
forall (v :: * -> *) a (m :: * -> *) k b.
(Vector v a, Monad m) =>
Series v k a -> (k -> a -> m b) -> m ()
G.forWithKeyM_


-- | \(O(n)\) Traverse a 'Series' with an Applicative action, taking into account both keys and values. 

traverseWithKey :: (Applicative t, Ord k)
                => (k -> a -> t b) 
                -> Series k a 
                -> t (Series k b)
{-# INLINABLE traverseWithKey #-}
traverseWithKey :: forall (t :: * -> *) k a b.
(Applicative t, Ord k) =>
(k -> a -> t b) -> Series k a -> t (Series k b)
traverseWithKey = (k -> a -> t b) -> Series Vector k a -> t (Series Vector k b)
forall (t :: * -> *) k (v :: * -> *) a b.
(Applicative t, Ord k, Traversable v, Vector v a, Vector v b,
 Vector v k, Vector v (k, a), Vector v (k, b)) =>
(k -> a -> t b) -> Series v k a -> t (Series v k b)
G.traverseWithKey


-- | \(O(\log n)\) @'take' n xs@ returns at most @n@ elements of the 'Series' @xs@.

--

-- >>> let xs = Series.fromList [("Paris", 1 :: Int), ("London", 2), ("Lisbon", 4), ("Vienna", 5)]

-- >>> xs

--    index | values

--    ----- | ------

-- "Lisbon" |      4

-- "London" |      2

--  "Paris" |      1

-- "Vienna" |      5

-- >>> take 2 xs

--    index | values

--    ----- | ------

-- "Lisbon" |      4

-- "London" |      2

take :: Int -> Series k a -> Series k a
{-# INLINABLE take #-}
take :: forall k a. Int -> Series k a -> Series k a
take = Int -> Series Vector k a -> Series Vector k a
forall (v :: * -> *) a k.
Vector v a =>
Int -> Series v k a -> Series v k a
G.take


-- | \(O(n)\) Returns the longest prefix (possibly empty) of the input 'Series' that satisfy a predicate.

--

-- >>> let xs = Series.fromList [("Paris", 1 :: Int), ("London", 2), ("Lisbon", 4), ("Vienna", 5)]

-- >>> xs

--    index | values

--    ----- | ------

-- "Lisbon" |      4

-- "London" |      2

--  "Paris" |      1

-- "Vienna" |      5


-- >>> takeWhile (>1) xs

--    index | values

--    ----- | ------

-- "Lisbon" |      4

-- "London" |      2

takeWhile :: (a -> Bool) -> Series k a -> Series k a
takeWhile :: forall a k. (a -> Bool) -> Series k a -> Series k a
takeWhile = (a -> Bool) -> Series Vector k a -> Series Vector k a
forall (v :: * -> *) a k.
Vector v a =>
(a -> Bool) -> Series v k a -> Series v k a
G.takeWhile


-- | \(O(\log n)\) @'drop' n xs@ drops at most @n@ elements from the 'Series' @xs@.

--

-- >>> let xs = Series.fromList [("Paris", 1 :: Int), ("London", 2), ("Lisbon", 4), ("Vienna", 5)]

-- >>> xs

--    index | values

--    ----- | ------

-- "Lisbon" |      4

-- "London" |      2

--  "Paris" |      1

-- "Vienna" |      5

-- >>> drop 2 xs

--    index | values

--    ----- | ------

--  "Paris" |      1

-- "Vienna" |      5

drop :: Int -> Series k a -> Series k a
{-# INLINABLE drop #-}
drop :: forall k a. Int -> Series k a -> Series k a
drop = Int -> Series Vector k a -> Series Vector k a
forall (v :: * -> *) a k.
Vector v a =>
Int -> Series v k a -> Series v k a
G.drop


-- | \(O(n)\) Returns the complement of `takeWhile`.

--

-- >>> let xs = Series.fromList [("Paris", 1 :: Int), ("London", 2), ("Lisbon", 4), ("Vienna", 5)]

-- >>> xs

--    index | values

--    ----- | ------

-- "Lisbon" |      4

-- "London" |      2

--  "Paris" |      1

-- "Vienna" |      5


-- >>> dropWhile (>1) xs

--    index | values

--    ----- | ------

--  "Paris" |      1

-- "Vienna" |      5

dropWhile :: (a -> Bool) -> Series k a -> Series k a
dropWhile :: forall a k. (a -> Bool) -> Series k a -> Series k a
dropWhile = (a -> Bool) -> Series Vector k a -> Series Vector k a
forall (v :: * -> *) a k.
Vector v a =>
(a -> Bool) -> Series v k a -> Series v k a
G.dropWhile


-- | Apply a function elementwise to two series, matching elements

-- based on their keys. For keys present only in the left or right series, 

-- the value 'Nothing' is returned.

--

-- >>> let xs = Series.fromList [ ("alpha", 0::Int), ("beta", 1), ("gamma", 2) ]

-- >>> let ys = Series.fromList [ ("alpha", 10::Int), ("beta", 11), ("delta", 13) ]

-- >>> zipWith (+) xs ys

--   index |  values

--   ----- |  ------

-- "alpha" | Just 10

--  "beta" | Just 12

-- "delta" | Nothing

-- "gamma" | Nothing

--

-- To only combine elements where keys are in both series, see 'zipWithMatched'.

zipWith :: (Ord k) 
        => (a -> b -> c) -> Series k a -> Series k b -> Series k (Maybe c)
zipWith :: forall k a b c.
Ord k =>
(a -> b -> c) -> Series k a -> Series k b -> Series k (Maybe c)
zipWith = (a -> b -> c)
-> Series Vector k a
-> Series Vector k b
-> Series Vector k (Maybe c)
forall (v :: * -> *) a b c k.
(Vector v a, Vector v b, Vector v c, Vector v (Maybe c), Ord k) =>
(a -> b -> c)
-> Series v k a -> Series v k b -> Series v k (Maybe c)
G.zipWith 
{-# INLINABLE zipWith #-}



-- | Apply a function elementwise to three series, matching elements

-- based on their keys. For keys present only in the left or right series, 

-- the value 'Nothing' is returned.

--

-- >>> let xs = Series.fromList [ ("alpha", 0::Int),  ("beta", 1),   ("gamma", 2) ]

-- >>> let ys = Series.fromList [ ("alpha", 10::Int), ("beta", 11),  ("delta", 13) ]

-- >>> let zs = Series.fromList [ ("alpha", 20::Int), ("delta", 13), ("epsilon", 6) ]

-- >>> zipWith3 (\x y z -> x + y + z) xs ys zs

--     index |  values

--     ----- |  ------

--   "alpha" | Just 30

--    "beta" | Nothing

--   "delta" | Nothing

-- "epsilon" | Nothing

--   "gamma" | Nothing

--

-- To only combine elements where keys are in all series, see 'zipWithMatched3'

zipWith3 :: (Ord k) 
         => (a -> b -> c -> d) 
         -> Series k a 
         -> Series k b 
         -> Series k c 
         -> Series k (Maybe d)
{-# INLINABLE zipWith3 #-}
zipWith3 :: forall k a b c d.
Ord k =>
(a -> b -> c -> d)
-> Series k a -> Series k b -> Series k c -> Series k (Maybe d)
zipWith3 = (a -> b -> c -> d)
-> Series Vector k a
-> Series Vector k b
-> Series Vector k c
-> Series Vector k (Maybe d)
forall (v :: * -> *) a b c d k.
(Vector v a, Vector v b, Vector v c, Vector v d,
 Vector v (Maybe d), Ord k) =>
(a -> b -> c -> d)
-> Series v k a
-> Series v k b
-> Series v k c
-> Series v k (Maybe d)
G.zipWith3


-- | Apply a function elementwise to two series, matching elements

-- based on their keys. Keys present only in the left or right series are dropped.

--

-- >>> let xs = Series.fromList [ ("alpha", 0::Int), ("beta", 1), ("gamma", 2) ]

-- >>> let ys = Series.fromList [ ("alpha", 10::Int), ("beta", 11), ("delta", 13) ]

-- >>> zipWithMatched (+) xs ys

--   index | values

--   ----- | ------

-- "alpha" |     10

--  "beta" |     12

--

-- To combine elements where keys are in either series, see 'zipWith'.

zipWithMatched :: Ord k => (a -> b -> c) -> Series k a -> Series k b -> Series k c
{-# INLINABLE zipWithMatched #-}
zipWithMatched :: forall k a b c.
Ord k =>
(a -> b -> c) -> Series k a -> Series k b -> Series k c
zipWithMatched = (a -> b -> c)
-> Series Vector k a -> Series Vector k b -> Series Vector k c
forall (v :: * -> *) a b c k.
(Vector v a, Vector v b, Vector v c, Ord k) =>
(a -> b -> c) -> Series v k a -> Series v k b -> Series v k c
G.zipWithMatched


-- | Apply a function elementwise to three series, matching elements

-- based on their keys. Keys not present in all three series are dropped.

--

-- >>> let xs = Series.fromList [ ("alpha", 0::Int),  ("beta", 1),   ("gamma", 2) ]

-- >>> let ys = Series.fromList [ ("alpha", 10::Int), ("beta", 11),  ("delta", 13) ]

-- >>> let zs = Series.fromList [ ("alpha", 20::Int), ("delta", 13), ("epsilon", 6) ]

-- >>> zipWithMatched3 (\x y z -> x + y + z) xs ys zs

--   index | values

--   ----- | ------

-- "alpha" |     30

zipWithMatched3 :: (Ord k) 
                => (a -> b -> c -> d) 
                -> Series k a 
                -> Series k b 
                -> Series k c
                -> Series k d
{-# INLINABLE zipWithMatched3 #-}
zipWithMatched3 :: forall k a b c d.
Ord k =>
(a -> b -> c -> d)
-> Series k a -> Series k b -> Series k c -> Series k d
zipWithMatched3 = (a -> b -> c -> d)
-> Series Vector k a
-> Series Vector k b
-> Series Vector k c
-> Series Vector k d
forall (v :: * -> *) a b c d k.
(Vector v a, Vector v b, Vector v c, Vector v d, Ord k) =>
(a -> b -> c -> d)
-> Series v k a -> Series v k b -> Series v k c -> Series v k d
G.zipWithMatched3


-- | Apply a function elementwise to two series, matching elements

-- based on their keys. Keys present only in the left or right series are dropped.

--

-- To combine elements where keys are in either series, see 'zipWith'

zipWithKey :: (Ord k) 
           => (k -> a -> b -> c) -> Series k a -> Series k b -> Series k c
{-# INLINABLE zipWithKey #-}
zipWithKey :: forall k a b c.
Ord k =>
(k -> a -> b -> c) -> Series k a -> Series k b -> Series k c
zipWithKey = (k -> a -> b -> c)
-> Series Vector k a -> Series Vector k b -> Series Vector k c
forall (v :: * -> *) a b c k.
(Vector v a, Vector v b, Vector v c, Vector v k, Ord k) =>
(k -> a -> b -> c) -> Series v k a -> Series v k b -> Series v k c
G.zipWithKey


-- | Apply a function elementwise to three series, matching elements

-- based on their keys. Keys present only in the left or right series are dropped.

--

-- To combine elements where keys are in any series, see 'zipWith3'

zipWithKey3 :: (Ord k) 
            => (k -> a -> b -> c -> d) 
            -> Series k a 
            -> Series k b 
            -> Series k c
            -> Series k d
{-# INLINABLE zipWithKey3 #-}
zipWithKey3 :: forall k a b c d.
Ord k =>
(k -> a -> b -> c -> d)
-> Series k a -> Series k b -> Series k c -> Series k d
zipWithKey3 = (k -> a -> b -> c -> d)
-> Series Vector k a
-> Series Vector k b
-> Series Vector k c
-> Series Vector k d
forall (v :: * -> *) a b c d k.
(Vector v a, Vector v b, Vector v c, Vector v d, Vector v k,
 Ord k) =>
(k -> a -> b -> c -> d)
-> Series v k a -> Series v k b -> Series v k c -> Series v k d
G.zipWithKey3


-- | Zip two 'Series' with a combining function, applying a `ZipStrategy` when one key is present in one of the 'Series' but not both.

--

-- In the example below, we want to set the value to @-100@ (via @`constStrategy` (-100)@) for keys which are only present 

-- in the left 'Series', and drop keys (via `skipStrategy`) which are only present in the `right 'Series'  

--

-- >>> let xs = Series.fromList [ ("alpha", 0::Int), ("beta", 1), ("gamma", 2) ]

-- >>> let ys = Series.fromList [ ("alpha", 10::Int), ("beta", 11), ("delta", 13) ]

-- >>> zipWithStrategy (+) (constStrategy (-100)) skipStrategy  xs ys

--   index | values

--   ----- | ------

-- "alpha" |     10

--  "beta" |     12

-- "gamma" |   -100

--

-- Note that if you want to drop keys missing in either 'Series', it is faster to use @`zipWithMatched` f@ 

-- than using @`zipWithStrategy` f skipStrategy skipStrategy@.

zipWithStrategy :: (Ord k) 
               => (a -> b -> c)     -- ^ Function to combine values when present in both series

               -> ZipStrategy k a c -- ^ Strategy for when the key is in the left series but not the right

               -> ZipStrategy k b c -- ^ Strategy for when the key is in the right series but not the left

               -> Series k a
               -> Series k b 
               -> Series k c
{-# INLINABLE zipWithStrategy #-}
zipWithStrategy :: forall k a b c.
Ord k =>
(a -> b -> c)
-> ZipStrategy k a c
-> ZipStrategy k b c
-> Series k a
-> Series k b
-> Series k c
zipWithStrategy = (a -> b -> c)
-> ZipStrategy k a c
-> ZipStrategy k b c
-> Series Vector k a
-> Series Vector k b
-> Series Vector k c
forall (v :: * -> *) a b c k.
(Vector v a, Vector v b, Vector v c, Ord k) =>
(a -> b -> c)
-> ZipStrategy k a c
-> ZipStrategy k b c
-> Series v k a
-> Series v k b
-> Series v k c
G.zipWithStrategy


-- | Zip three 'Series' with a combining function, applying a 'ZipStrategy' when one key is 

-- present in one of the 'Series' but not all of the others.

--

-- Note that if you want to drop keys missing in either 'Series', it is faster to use @'zipWithMatched3' f@ 

-- than using @'zipWithStrategy3' f skipStrategy skipStrategy skipStrategy@.

zipWithStrategy3 :: (Ord k) 
                => (a -> b -> c -> d) -- ^ Function to combine values when present in all series

                -> ZipStrategy k a d  -- ^ Strategy for when the key is in the left series but not in all the others

                -> ZipStrategy k b d  -- ^ Strategy for when the key is in the center series but not in all the others

                -> ZipStrategy k c d  -- ^ Strategy for when the key is in the right series but not in all the others

                -> Series k a
                -> Series k b 
                -> Series k c
                -> Series k d
{-# INLINABLE zipWithStrategy3 #-}
zipWithStrategy3 :: forall k a b c d.
Ord k =>
(a -> b -> c -> d)
-> ZipStrategy k a d
-> ZipStrategy k b d
-> ZipStrategy k c d
-> Series k a
-> Series k b
-> Series k c
-> Series k d
zipWithStrategy3 = (a -> b -> c -> d)
-> ZipStrategy k a d
-> ZipStrategy k b d
-> ZipStrategy k c d
-> Series Vector k a
-> Series Vector k b
-> Series Vector k c
-> Series Vector k d
forall (v :: * -> *) a b c d k.
(Vector v a, Vector v b, Vector v c, Vector v d, Ord k) =>
(a -> b -> c -> d)
-> ZipStrategy k a d
-> ZipStrategy k b d
-> ZipStrategy k c d
-> Series v k a
-> Series v k b
-> Series v k c
-> Series v k d
G.zipWithStrategy3


-- | Zip two 'Series' with a combining function. The value for keys which are missing from

-- either 'Series' is replaced with the appropriate `mempty` value.

--

-- >>> import Data.Monoid ( Sum(..) )

-- >>> let xs = Series.fromList [ ("2023-01-01", Sum (1::Int)), ("2023-01-02", Sum 2) ]

-- >>> let ys = Series.fromList [ ("2023-01-01", Sum (5::Int)), ("2023-01-03", Sum 7) ]

-- >>> Series.zipWith (<>) xs ys

--        index |                  values

--        ----- |                  ------

-- "2023-01-01" | Just (Sum {getSum = 6})

-- "2023-01-02" |                 Nothing

-- "2023-01-03" |                 Nothing

-- >>> zipWithMonoid (<>) xs ys

--        index |           values

--        ----- |           ------

-- "2023-01-01" | Sum {getSum = 6}

-- "2023-01-02" | Sum {getSum = 2}

-- "2023-01-03" | Sum {getSum = 7}

zipWithMonoid :: ( Monoid a, Monoid b, Ord k) 
              => (a -> b -> c)
              -> Series k a
              -> Series k b 
              -> Series k c
zipWithMonoid :: forall a b k c.
(Monoid a, Monoid b, Ord k) =>
(a -> b -> c) -> Series k a -> Series k b -> Series k c
zipWithMonoid = (a -> b -> c)
-> Series Vector k a -> Series Vector k b -> Series Vector k c
forall a b (v :: * -> *) c k.
(Monoid a, Monoid b, Vector v a, Vector v b, Vector v c, Ord k) =>
(a -> b -> c) -> Series v k a -> Series v k b -> Series v k c
G.zipWithMonoid
{-# INLINABLE zipWithMonoid #-}


-- | Elementwise sum of two 'Series'. Elements missing in one or the other 'Series' is considered 0. 

--

-- >>> let xs = Series.fromList [ ("2023-01-01", (1::Int)), ("2023-01-02", 2) ]

-- >>> let ys = Series.fromList [ ("2023-01-01", (5::Int)), ("2023-01-03", 7) ]

-- >>> xs `esum` ys

--        index | values

--        ----- | ------

-- "2023-01-01" |      6

-- "2023-01-02" |      2

-- "2023-01-03" |      7

esum :: (Ord k, Num a) 
     => Series k a 
     -> Series k a
     -> Series k a
esum :: forall k a.
(Ord k, Num a) =>
Series k a -> Series k a -> Series k a
esum = Series Vector k a -> Series Vector k a -> Series Vector k a
forall k a (v :: * -> *).
(Ord k, Num a, Vector v a, Vector v (Sum a)) =>
Series v k a -> Series v k a -> Series v k a
G.esum
{-# INLINABLE esum #-}


-- | Elementwise product of two 'Series'. Elements missing in one or the other 'Series' is considered 1. 

--

-- >>> let xs = Series.fromList [ ("2023-01-01", (2::Int)), ("2023-01-02", 3) ]

-- >>> let ys = Series.fromList [ ("2023-01-01", (5::Int)), ("2023-01-03", 7) ]

-- >>> xs `eproduct` ys

--        index | values

--        ----- | ------

-- "2023-01-01" |     10

-- "2023-01-02" |      3

-- "2023-01-03" |      7

eproduct :: (Ord k, Num a) 
         => Series k a 
         -> Series k a
         -> Series k a
eproduct :: forall k a.
(Ord k, Num a) =>
Series k a -> Series k a -> Series k a
eproduct = Series Vector k a -> Series Vector k a -> Series Vector k a
forall k a (v :: * -> *).
(Ord k, Num a, Vector v a, Vector v (Product a)) =>
Series v k a -> Series v k a -> Series v k a
G.eproduct
{-# INLINABLE eproduct #-}


-- | \(O(n)\) Unzip a 'Series' of 2-tuples.

unzip :: Series k (a, b)
      -> ( Series k a
         , Series k b
         )
unzip :: forall k a b. Series k (a, b) -> (Series k a, Series k b)
unzip = Series Vector k (a, b) -> (Series Vector k a, Series Vector k b)
forall (v :: * -> *) a b k.
(Vector v a, Vector v b, Vector v (a, b)) =>
Series v k (a, b) -> (Series v k a, Series v k b)
G.unzip
{-# INLINABLE unzip #-}


-- | \(O(n)\) Unzip a 'Series' of 3-tuples.

unzip3 :: Series k (a, b, c)
       -> ( Series k a
          , Series k b
          , Series k c
          )
unzip3 :: forall k a b c.
Series k (a, b, c) -> (Series k a, Series k b, Series k c)
unzip3 = Series Vector k (a, b, c)
-> (Series Vector k a, Series Vector k b, Series Vector k c)
forall (v :: * -> *) a b c k.
(Vector v a, Vector v b, Vector v c, Vector v (a, b, c)) =>
Series v k (a, b, c) -> (Series v k a, Series v k b, Series v k c)
G.unzip3
{-# INLINABLE unzip3 #-}


-- | Require a series to have a specific `Index`.

-- Contrary to @select@, all keys in the `Index` will be present in the resulting series.

--

-- >>> let xs = Series.fromList [("Paris", 1 :: Int), ("London", 2), ("Lisbon", 4)]

-- >>> xs

--    index | values

--    ----- | ------

-- "Lisbon" |      4

-- "London" |      2

--  "Paris" |      1

-- >>> xs `require` Index.fromList ["Paris", "Lisbon", "Taipei"]

--    index |  values

--    ----- |  ------

-- "Lisbon" |  Just 4

--  "Paris" |  Just 1

-- "Taipei" | Nothing

require :: Ord k => Series k a -> Index k -> Series k (Maybe a)
{-# INLINABLE require #-}
require :: forall k a. Ord k => Series k a -> Index k -> Series k (Maybe a)
require = Series Vector k a -> Index k -> Series Vector k (Maybe a)
forall (v :: * -> *) a k.
(Vector v a, Vector v (Maybe a), Ord k) =>
Series v k a -> Index k -> Series v k (Maybe a)
G.require 


-- | \(O(n)\) Drop the index of a series by replacing it with an `Int`-based index. Values will

-- be indexed from 0.

--

-- >>> let xs = Series.fromList [("Paris", 1 :: Int), ("London", 2), ("Lisbon", 4)]

-- >>> xs

--    index | values

--    ----- | ------

-- "Lisbon" |      4

-- "London" |      2

--  "Paris" |      1

-- >>> dropIndex xs

-- index | values

-- ----- | ------

--     0 |      4

--     1 |      2

--     2 |      1

dropIndex :: Series k a -> Series Int a
{-# INLINABLE dropIndex #-}
dropIndex :: forall k a. Series k a -> Series Int a
dropIndex = Series Vector k a -> Series Vector Int a
forall {k1} (v :: k1 -> *) k2 (a :: k1).
Series v k2 a -> Series v Int a
G.dropIndex


-- | Filter elements. Only elements for which the predicate is @True@ are kept. 

-- Notice that the filtering is done on the values, not on the keys.

--

-- >>> let xs = Series.fromList [("Paris", 1 :: Int), ("London", 2), ("Lisbon", 4)]

-- >>> xs

--    index | values

--    ----- | ------

-- "Lisbon" |      4

-- "London" |      2

--  "Paris" |      1

-- >>> filter (>2) xs

--    index | values

--    ----- | ------

-- "Lisbon" |      4

--

-- See also 'filterWithKey'.

filter :: Ord k => (a -> Bool) -> Series k a -> Series k a
{-# INLINABLE filter #-}
filter :: forall k a. Ord k => (a -> Bool) -> Series k a -> Series k a
filter = (a -> Bool) -> Series Vector k a -> Series Vector k a
forall (v :: * -> *) a k.
(Vector v a, Vector v Int, Ord k) =>
(a -> Bool) -> Series v k a -> Series v k a
G.filter


-- | Filter elements, taking into account the corresponding key. Only elements for which 

-- the predicate is @True@ are kept. 

filterWithKey :: Ord k 
              => (k -> a -> Bool) 
              -> Series k a 
              -> Series k a
{-# INLINABLE filterWithKey #-}
filterWithKey :: forall k a. Ord k => (k -> a -> Bool) -> Series k a -> Series k a
filterWithKey = (k -> a -> Bool) -> Series Vector k a -> Series Vector k a
forall (v :: * -> *) a k.
(Vector v a, Vector v Int, Vector v Bool, Ord k) =>
(k -> a -> Bool) -> Series v k a -> Series v k a
G.filterWithKey


-- | Drop elements which are not available (NA). 

--

-- >>> let xs = Series.fromList [("Paris", 1 :: Int), ("London", 2), ("Lisbon", 4)]

-- >>> let ys = xs `require` Index.fromList ["Paris", "London", "Lisbon", "Toronto"]

-- >>> ys

--     index |  values

--     ----- |  ------

--  "Lisbon" |  Just 4

--  "London" |  Just 2

--   "Paris" |  Just 1

-- "Toronto" | Nothing

-- >>> catMaybes ys

--    index | values

--    ----- | ------

-- "Lisbon" |      4

-- "London" |      2

--  "Paris" |      1

catMaybes :: Ord k => Series k (Maybe a) -> Series k a
{-# INLINABLE catMaybes #-}
catMaybes :: forall k a. Ord k => Series k (Maybe a) -> Series k a
catMaybes = Series Vector k (Maybe a) -> Series Vector k a
forall (v :: * -> *) a k.
(Vector v a, Vector v (Maybe a), Vector v Int, Ord k) =>
Series v k (Maybe a) -> Series v k a
G.catMaybes


-- | Select a subseries. There are a few ways to do this.

--

-- The first way to do this is to select a sub-series based on random keys. For example,

-- selecting a subseries from an `Index`:

--

-- >>> let xs = Series.fromList [('a', 10::Int), ('b', 20), ('c', 30), ('d', 40)]

-- >>> xs `select` Index.fromList ['a', 'd']

-- index | values

-- ----- | ------

--   'a' |     10

--   'd' |     40

--

-- The second way to select a sub-series is to select all keys in a range:

--

-- >>> xs `select` 'b' `to` 'c'

-- index | values

-- ----- | ------

--   'b' |     20

--   'c' |     30

--

-- Note that with `select`, you'll always get a sub-series; if you ask for a key which is not

-- in the series, it'll be ignored:

--

-- >>> xs `select` Index.fromList ['a', 'd', 'e']

-- index | values

-- ----- | ------

--   'a' |     10

--   'd' |     40

--

-- See `require` if you want to ensure that all keys are present.

select :: (Selection s, Ord k) => Series k a -> s k -> Series k a
select :: forall (s :: * -> *) k a.
(Selection s, Ord k) =>
Series k a -> s k -> Series k a
select = Series Vector k a -> s k -> Series Vector k a
forall (s :: * -> *) (v :: * -> *) a k.
(Selection s, Vector v a, Ord k) =>
Series v k a -> s k -> Series v k a
forall (v :: * -> *) a k.
(Vector v a, Ord k) =>
Series v k a -> s k -> Series v k a
G.select


-- | Select a sub-series from a series matching a condition.

--

-- >>> let xs = Series.fromList [("Paris", 1 :: Int), ("London", 2), ("Lisbon", 4)]

-- >>> xs

--    index | values

--    ----- | ------

-- "Lisbon" |      4

-- "London" |      2

--  "Paris" |      1

-- >>> xs `selectWhere` (fmap (>1) xs)

--    index | values

--    ----- | ------

-- "Lisbon" |      4

-- "London" |      2

selectWhere :: Ord k => Series k a -> Series k Bool -> Series k a
{-# INLINABLE selectWhere #-}
selectWhere :: forall k a. Ord k => Series k a -> Series k Bool -> Series k a
selectWhere = Series Vector k a -> Series Vector k Bool -> Series Vector k a
forall (v :: * -> *) a k.
(Vector v a, Vector v Int, Vector v Bool, Ord k) =>
Series v k a -> Series v k Bool -> Series v k a
G.selectWhere


-- | \(O(\log n)\). Extract a single value from a series, by key.

--

-- >>> let xs = Series.fromList [("Paris", 1 :: Int), ("London", 2), ("Lisbon", 4)]

-- >>> xs `at` "Paris"

-- Just 1

-- >>> xs `at` "Sydney"

-- Nothing

at :: Ord k => Series k a -> k -> Maybe a
{-# INLINABLE at #-}
at :: forall k a. Ord k => Series k a -> k -> Maybe a
at = Series Vector k a -> k -> Maybe a
forall (v :: * -> *) a k.
(Vector v a, Ord k) =>
Series v k a -> k -> Maybe a
G.at


-- | \(O(1)\). Extract a single value from a series, by index.

--

-- >>> let xs = Series.fromList [("Paris", 1 :: Int), ("London", 2), ("Lisbon", 4)]

-- >>> xs

--    index | values

--    ----- | ------

-- "Lisbon" |      4

-- "London" |      2

--  "Paris" |      1

-- >>> xs `iat` 0

-- Just 4

-- >>> xs `iat` 3

-- Nothing

iat :: Series k a -> Int -> Maybe a
{-# INLINABLE iat #-}
iat :: forall k a. Series k a -> Int -> Maybe a
iat = Series Vector k a -> Int -> Maybe a
forall (v :: * -> *) a k.
Vector v a =>
Series v k a -> Int -> Maybe a
G.iat


-- | Replace values in the right series from values in the left series at matching keys.

-- Keys not in the right series are unaffected.

-- 

-- See `(|->)` and `(<-|)`, which might be more readable.

--

-- >>> let xs = Series.fromList [("Paris", 1 :: Int), ("London", 2), ("Lisbon", 4)]

-- >>> xs

--    index | values

--    ----- | ------

-- "Lisbon" |      4

-- "London" |      2

--  "Paris" |      1

-- >>> let ys = Series.singleton "Paris" (99::Int)

-- >>> ys `replace` xs

--    index | values

--    ----- | ------

-- "Lisbon" |      4

-- "London" |      2

--  "Paris" |     99

replace :: Ord k => Series k a -> Series k a -> Series k a
{-# INLINABLE replace #-}
replace :: forall k a. Ord k => Series k a -> Series k a -> Series k a
replace = Series Vector k a -> Series Vector k a -> Series Vector k a
forall (v :: * -> *) a k.
(Vector v a, Vector v Int, Ord k) =>
Series v k a -> Series v k a -> Series v k a
G.replace


-- | Replace values in the right series from values in the left series at matching keys.

-- Keys not in the right series are unaffected.

--

-- >>> let xs = Series.fromList [("Paris", 1 :: Int), ("London", 2), ("Lisbon", 4)]

-- >>> xs

--    index | values

--    ----- | ------

-- "Lisbon" |      4

-- "London" |      2

--  "Paris" |      1

-- >>> let ys = Series.singleton "Paris" (99::Int)

-- >>> ys |-> xs

--    index | values

--    ----- | ------

-- "Lisbon" |      4

-- "London" |      2

--  "Paris" |     99

(|->) :: (Ord k) => Series k a -> Series k a -> Series k a
{-# INLINABLE (|->) #-}
|-> :: forall k a. Ord k => Series k a -> Series k a -> Series k a
(|->) = Series Vector k a -> Series Vector k a -> Series Vector k a
forall (v :: * -> *) a k.
(Vector v a, Vector v Int, Ord k) =>
Series v k a -> Series v k a -> Series v k a
(G.|->)


-- | Replace values in the left series from values in the right series at matching keys.

-- Keys not in the left series are unaffected.

--

-- >>> let xs = Series.fromList [("Paris", 1 :: Int), ("London", 2), ("Lisbon", 4)]

-- >>> xs

--    index | values

--    ----- | ------

-- "Lisbon" |      4

-- "London" |      2

--  "Paris" |      1

-- >>> let ys = Series.singleton "Paris" (99::Int)

-- >>> xs <-| ys

--    index | values

--    ----- | ------

-- "Lisbon" |      4

-- "London" |      2

--  "Paris" |     99

(<-|) :: (Ord k) => Series k a -> Series k a -> Series k a
{-# INLINABLE (<-|) #-}
<-| :: forall k a. Ord k => Series k a -> Series k a -> Series k a
(<-|) = Series Vector k a -> Series Vector k a -> Series Vector k a
forall (v :: * -> *) a k.
(Vector v a, Vector v Int, Ord k) =>
Series v k a -> Series v k a -> Series v k a
(G.<-|)


-- | \(O(n)\) Replace all instances of 'Nothing' with the last previous

-- value which was not 'Nothing'.

--

-- >>> let xs = Series.fromList (zip [0..] [Just 1, Just 2,Nothing, Just 3]) :: Series Int (Maybe Int)

-- >>> xs

-- index |  values

-- ----- |  ------

--     0 |  Just 1

--     1 |  Just 2

--     2 | Nothing

--     3 |  Just 3

-- >>> forwardFill 0 xs

-- index | values

-- ----- | ------

--     0 |      1

--     1 |      2

--     2 |      2

--     3 |      3

--

-- If the first entry of the series is missing, the first input to 'forwardFill' will be used:

--

-- >>> let ys = Series.fromList (zip [0..] [Nothing, Just 2,Nothing, Just 3]) :: Series Int (Maybe Int)

-- >>> ys

-- index |  values

-- ----- |  ------

--     0 | Nothing

--     1 |  Just 2

--     2 | Nothing

--     3 |  Just 3

-- >>> forwardFill 0 ys

-- index | values

-- ----- | ------

--     0 |      0

--     1 |      2

--     2 |      2

--     3 |      3

forwardFill :: a -- ^ Until the first non-'Nothing' is found, 'Nothing' will be filled with this value.

            -> Series v (Maybe a)
            -> Series v a
{-# INLINABLE forwardFill #-}
forwardFill :: forall a v. a -> Series v (Maybe a) -> Series v a
forwardFill = a -> Series Vector v (Maybe a) -> Series Vector v a
forall (v :: * -> *) a k.
(Vector v a, Vector v (Maybe a)) =>
a -> Series v k (Maybe a) -> Series v k a
G.forwardFill


-- | \(O(n)\) Execute a 'Fold' over a 'Series'.

--

-- >>> let xs = Series.fromList (zip [0..] [1,2,3,4]) :: Series Int Double

-- >>> xs

-- index | values

-- ----- | ------

--     0 |    1.0

--     1 |    2.0

--     2 |    3.0

--     3 |    4.0

-- >>> import Control.Foldl (variance)

-- >>> fold variance xs

-- 1.25

--

-- See also 'foldM' for monadic folds, and 'foldWithKey' to take keys into

-- account while folding.

fold :: Fold a b -> Series k a -> b
fold :: forall a b k. Fold a b -> Series k a -> b
fold = Fold a b -> Series Vector k a -> b
forall (v :: * -> *) a b k.
Vector v a =>
Fold a b -> Series v k a -> b
G.fold
{-# INLINABLE fold #-}


-- | \(O(n)\) Execute a monadic 'FoldM' over a 'Series'.

--

-- See also 'fold' for pure folds, and 'foldMWithKey' to take keys into

-- account while folding.

foldM :: (Monad m) 
      => FoldM m a b  
      -> Series k a 
      -> m b
foldM :: forall (m :: * -> *) a b k.
Monad m =>
FoldM m a b -> Series k a -> m b
foldM = FoldM m a b -> Series Vector k a -> m b
forall (m :: * -> *) (v :: * -> *) a b k.
(Monad m, Vector v a) =>
FoldM m a b -> Series v k a -> m b
G.foldM
{-# INLINABLE foldM #-}


-- | \(O(n)\) Execute a 'Fold' over a 'Series', taking keys into account.

foldWithKey :: Fold (k, a) b -> Series k a -> b
foldWithKey :: forall k a b. Fold (k, a) b -> Series k a -> b
foldWithKey = Fold (k, a) b -> Series Vector k a -> b
forall (v :: * -> *) a k b.
(Vector v a, Vector v k, Vector v (k, a)) =>
Fold (k, a) b -> Series v k a -> b
G.foldWithKey
{-# INLINABLE foldWithKey #-}


-- | \(O(n)\) Execute a monadic 'FoldM' over a 'Series', where the 'FoldM' takes keys into account.

foldMWithKey :: (Monad m) 
             => FoldM m (k, a) b  
             -> Series k a 
             -> m b
foldMWithKey :: forall (m :: * -> *) k a b.
Monad m =>
FoldM m (k, a) b -> Series k a -> m b
foldMWithKey = FoldM m (k, a) b -> Series Vector k a -> m b
forall (m :: * -> *) (v :: * -> *) a k b.
(Monad m, Vector v a, Vector v k, Vector v (k, a)) =>
FoldM m (k, a) b -> Series v k a -> m b
G.foldMWithKey
{-# INLINABLE foldMWithKey #-}


-- | \(O(n)\) Map each element and associated key of the structure to a monoid and combine

-- the results.

foldMapWithKey :: Monoid m => (k -> a -> m) -> Series k a -> m
{-# INLINABLE foldMapWithKey #-}
foldMapWithKey :: forall m k a. Monoid m => (k -> a -> m) -> Series k a -> m
foldMapWithKey = (k -> a -> m) -> Series Vector k a -> m
forall m (v :: * -> *) a k.
(Monoid m, Vector v a, Vector v k, Vector v (k, a)) =>
(k -> a -> m) -> Series v k a -> m
G.foldMapWithKey


-- | Group values in a 'Series' by some grouping function (@k -> g@).

-- The provided grouping function is guaranteed to operate on a non-empty 'Series'.

--

-- This function is expected to be used in conjunction with 'aggregateWith':

-- 

-- >>> import Data.Maybe ( fromMaybe )

-- >>> type Date = (Int, String)

-- >>> month :: (Date -> String) = snd

-- >>> :{ 

--     let xs = Series.fromList [ ((2020, "January") :: Date,  0 :: Int)

--                              , ((2021, "January"), -5)

--                              , ((2020, "June")   , 20)

--                              , ((2021, "June")   , 25) 

--                              ]

--      in xs `groupBy` month `aggregateWith` (fromMaybe 0 . minimum)

-- :}

--     index | values

--     ----- | ------

-- "January" |     -5

--    "June" |     20

groupBy :: Series k a      -- ^ Grouping function

        ->(k -> g)         -- ^ Input series

        -> Grouping k g a  -- ^ Grouped series

{-# INLINABLE groupBy #-}
groupBy :: forall k a g. Series k a -> (k -> g) -> Grouping k g a
groupBy = Series Vector k a -> (k -> g) -> Grouping k g Vector a
forall {k1} (v :: k1 -> *) k2 (a :: k1) g.
Series v k2 a -> (k2 -> g) -> Grouping k2 g v a
G.groupBy

-- | Representation of a 'Series' being grouped.

type Grouping k g a = G.Grouping k g Vector a


-- | Aggregate groups resulting from a call to 'groupBy':

-- 

-- >>> import Data.Maybe ( fromMaybe )

-- >>> type Date = (Int, String)

-- >>> month :: (Date -> String) = snd

-- >>> :{ 

--     let xs = Series.fromList [ ((2020, "January") :: Date,  0 :: Int)

--                              , ((2021, "January"), -5)

--                              , ((2020, "June")   , 20)

--                              , ((2021, "June")   , 25) 

--                              ]

--      in xs `groupBy` month `aggregateWith` (fromMaybe 0 . minimum)

-- :}

--     index | values

--     ----- | ------

-- "January" |     -5

--    "June" |     20

--

-- If you want to aggregate groups using a binary function, see 'foldWith' which

-- may be much faster.

aggregateWith :: (Ord g) 
              => Grouping k g a 
              -> (Series k a -> b) 
              -> Series g b
{-# INLINABLE aggregateWith #-}
aggregateWith :: forall g k a b.
Ord g =>
Grouping k g a -> (Series k a -> b) -> Series g b
aggregateWith = Grouping k g Vector a
-> (Series Vector k a -> b) -> Series Vector g b
forall g (v :: * -> *) a b k.
(Ord g, Vector v a, Vector v b) =>
Grouping k g v a -> (Series v k a -> b) -> Series v g b
G.aggregateWith


-- | Aggregate each group in a 'Grouping' using a binary function.

-- While this is not as expressive as 'aggregateWith', users looking for maximum

-- performance should use 'foldWith' as much as possible.

foldWith :: Ord g 
         => Grouping k g a
         -> (a -> a -> a)
         -> Series g a
{-# INLINABLE foldWith #-}
foldWith :: forall g k a.
Ord g =>
Grouping k g a -> (a -> a -> a) -> Series g a
foldWith = Grouping k g Vector a -> (a -> a -> a) -> Series Vector g a
forall g (v :: * -> *) a k.
(Ord g, Vector v a) =>
Grouping k g v a -> (a -> a -> a) -> Series v g a
G.foldWith


-- | Expanding window aggregation.

--

-- >>> import qualified Data.Series as Series 

-- >>> :{ 

--     let (xs :: Series.Series Int Int) 

--          = Series.fromList [ (1, 0)

--                            , (2, 1)

--                            , (3, 2)

--                            , (4, 3)

--                            , (5, 4)

--                            , (6, 5)

--                            ]

--     in (xs `expanding` sum) :: Series.Series Int Int 

-- :}

-- index | values

-- ----- | ------

--     1 |      0

--     2 |      1

--     3 |      3

--     4 |      6

--     5 |     10

--     6 |     15

expanding :: Series k a        -- ^ Series vector

          -> (Series k a -> b) -- ^ Aggregation function

          -> Series k b        -- ^ Resulting vector

{-# INLINABLE expanding #-}
expanding :: forall k a b. Series k a -> (Series k a -> b) -> Series k b
expanding = Series Vector k a -> (Series Vector k a -> b) -> Series Vector k b
forall (v :: * -> *) a b k.
(Vector v a, Vector v b) =>
Series v k a -> (Series v k a -> b) -> Series v k b
G.expanding


-- | General-purpose window aggregation.

--

-- >>> import qualified Data.Series as Series 

-- >>> :{ 

--     let (xs :: Series.Series Int Int) 

--          = Series.fromList [ (1, 0)

--                            , (2, 1)

--                            , (3, 2)

--                            , (4, 3)

--                            , (5, 4)

--                            , (6, 5)

--                            ]

--     in windowing (\k -> k `to` (k+2)) sum xs

-- :}

-- index | values

-- ----- | ------

--     1 |      3

--     2 |      6

--     3 |      9

--     4 |     12

--     5 |      9

--     6 |      5

windowing :: Ord k
          => (k -> Range k)
          -> (Series k a -> b)
          -> Series k a
          -> Series k b
{-# INLINABLE windowing #-}
windowing :: forall k a b.
Ord k =>
(k -> Range k) -> (Series k a -> b) -> Series k a -> Series k b
windowing = (k -> Range k)
-> (Series Vector k a -> b)
-> Series Vector k a
-> Series Vector k b
forall k (v :: * -> *) a b.
(Ord k, Vector v a, Vector v b) =>
(k -> Range k)
-> (Series v k a -> b) -> Series v k a -> Series v k b
G.windowing


-- | \(O(1)\) Test whether a 'Series' is empty.

null :: Series k a -> Bool
{-# INLINABLE null #-}
null :: forall k a. Series k a -> Bool
null = Series Vector k a -> Bool
forall (v :: * -> *) a k. Vector v a => Series v k a -> Bool
G.null


-- |\(O(1)\) Extract the length of a 'Series'.

length :: Series k a -> Int
{-# INLINABLE length #-}
length :: forall k a. Series k a -> Int
length = Series Vector k a -> Int
forall (v :: * -> *) a k. Vector v a => Series v k a -> Int
G.length


-- | \(O(n)\) Check if all elements satisfy the predicate.

all :: (a -> Bool) -> Series k a -> Bool
{-# INLINABLE all #-}
all :: forall a k. (a -> Bool) -> Series k a -> Bool
all = (a -> Bool) -> Series Vector k a -> Bool
forall (v :: * -> *) a k.
Vector v a =>
(a -> Bool) -> Series v k a -> Bool
G.all


-- | \(O(n)\) Check if any element satisfies the predicate.

any :: (a -> Bool) -> Series k a -> Bool
{-# INLINABLE any #-}
any :: forall a k. (a -> Bool) -> Series k a -> Bool
any = (a -> Bool) -> Series Vector k a -> Bool
forall (v :: * -> *) a k.
Vector v a =>
(a -> Bool) -> Series v k a -> Bool
G.any


-- | \(O(n)\) Check if all elements are 'True'.

and :: Series k Bool -> Bool
{-# INLINABLE and #-}
and :: forall k. Series k Bool -> Bool
and = Series Vector k Bool -> Bool
forall (v :: * -> *) k. Vector v Bool => Series v k Bool -> Bool
G.and


-- | \(O(n)\) Check if any element is 'True'.

or :: Series k Bool -> Bool
{-# INLINABLE or #-}
or :: forall k. Series k Bool -> Bool
or = Series Vector k Bool -> Bool
forall (v :: * -> *) k. Vector v Bool => Series v k Bool -> Bool
G.or


-- | \(O(n)\) Compute the sum of the elements.

sum :: (Num a) => Series k a -> a
{-# INLINABLE sum #-}
sum :: forall a k. Num a => Series k a -> a
sum = Series Vector k a -> a
forall a (v :: * -> *) k. (Num a, Vector v a) => Series v k a -> a
G.sum


-- | \(O(n)\) Compute the product of the elements.

product :: (Num a) => Series k a -> a
{-# INLINABLE product #-}
product :: forall a k. Num a => Series k a -> a
product = Series Vector k a -> a
forall a (v :: * -> *) k. (Num a, Vector v a) => Series v k a -> a
G.product


-- | \(O(n)\) Yield the maximum element of the series. In case of a tie, the first occurrence wins.

-- If the 'Series' is empty, @Nothing@ is returned.

--

-- See also 'argmax'.

maximum :: (Ord a) => Series k a -> Maybe a
{-# INLINABLE maximum #-}
maximum :: forall a k. Ord a => Series k a -> Maybe a
maximum = Series Vector k a -> Maybe a
forall a (v :: * -> *) k.
(Ord a, Vector v a) =>
Series v k a -> Maybe a
G.maximum


-- | \(O(n)\) @'maximumOn' f xs@ teturns the maximum element of the series @xs@, as determined by the function @f@.

-- In case of a tie, the first occurrence wins. If the 'Series' is empty, @Nothing@ is returned.

maximumOn :: (Ord b) => (a -> b) -> Series k a -> Maybe a
{-# INLINABLE maximumOn #-}
maximumOn :: forall b a k. Ord b => (a -> b) -> Series k a -> Maybe a
maximumOn = (a -> b) -> Series Vector k a -> Maybe a
forall b (v :: * -> *) a k.
(Ord b, Vector v a) =>
(a -> b) -> Series v k a -> Maybe a
G.maximumOn


-- | \(O(n)\) Yield the minimum element of the series. In case of a tie, the first occurrence wins.

-- If the 'Series' is empty, @Nothing@ is returned.

--

-- See also 'argmin'.

minimum :: (Ord a) => Series k a -> Maybe a
{-# INLINABLE minimum #-}
minimum :: forall a k. Ord a => Series k a -> Maybe a
minimum = Series Vector k a -> Maybe a
forall a (v :: * -> *) k.
(Ord a, Vector v a) =>
Series v k a -> Maybe a
G.minimum


-- | \(O(n)\) @'minimumOn' f xs@ teturns the minimum element of the series @xs@, as determined by the function @f@.

-- In case of a tie, the first occurrence wins. If the 'Series' is empty, @Nothing@ is returned.

minimumOn :: (Ord b) => (a -> b) -> Series k a -> Maybe a
{-# INLINABLE minimumOn #-}
minimumOn :: forall b a k. Ord b => (a -> b) -> Series k a -> Maybe a
minimumOn = (a -> b) -> Series Vector k a -> Maybe a
forall b (v :: * -> *) a k.
(Ord b, Vector v a) =>
(a -> b) -> Series v k a -> Maybe a
G.minimumOn


-- | \(O(n)\) Find the index of the maximum element in the input series.

-- If the input series is empty, 'Nothing' is returned.

--

-- The index of the first occurrence of the maximum element is returned.

--

-- >>> :{ 

--     let (xs :: Series Int Int) 

--          = Series.fromList [ (1, 0)

--                            , (2, 1)

--                            , (3, 2)

--                            , (4, 7)

--                            , (5, 4)

--                            , (6, 5)

--                            ]

--     in argmax xs 

-- :}

-- Just 4

argmax :: Ord a => Series k a -> Maybe k
argmax :: forall a k. Ord a => Series k a -> Maybe k
argmax = Series Vector k a -> Maybe k
forall a (v :: * -> *) k.
(Ord a, Vector v a) =>
Series v k a -> Maybe k
G.argmax
{-# INLINABLE argmax #-}


-- | \(O(n)\) Find the index of the minimum element in the input series.

-- If the input series is empty, 'Nothing' is returned.

--

-- The index of the first occurrence of the minimum element is returned.

-- >>> :{ 

--     let (xs :: Series Int Int) 

--          = Series.fromList [ (1, 1)

--                            , (2, 1)

--                            , (3, 2)

--                            , (4, 0)

--                            , (5, 4)

--                            , (6, 5)

--                            ]

--     in argmin xs 

-- :}

-- Just 4

argmin :: Ord a => Series k a -> Maybe k
argmin :: forall a k. Ord a => Series k a -> Maybe k
argmin = Series Vector k a -> Maybe k
forall a (v :: * -> *) k.
(Ord a, Vector v a, Vector v (Down a)) =>
Series v k a -> Maybe k
G.argmin
{-# INLINABLE argmin #-}


-- | \(O(n)\) Left-to-right postscan.

--

-- >>> let xs = Series.fromList (zip [0..] [1,2,3,4]) :: Series Int Int

-- >>> xs

-- index | values

-- ----- | ------

--     0 |      1

--     1 |      2

--     2 |      3

--     3 |      4

-- >>> postscanl (+) 0 xs

-- index | values

-- ----- | ------

--     0 |      1

--     1 |      3

--     2 |      6

--     3 |     10

postscanl :: (a -> b -> a) -> a -> Series k b -> Series k a
{-# INLINABLE postscanl #-}
postscanl :: forall a b k. (a -> b -> a) -> a -> Series k b -> Series k a
postscanl = (a -> b -> a) -> a -> Series Vector k b -> Series Vector k a
forall (v :: * -> *) a b k.
(Vector v a, Vector v b) =>
(a -> b -> a) -> a -> Series v k b -> Series v k a
G.postscanl


-- | \(O(n)\) Left-to-right prescan.

--

-- >>> let xs = Series.fromList (zip [0..] [1,2,3,4]) :: Series Int Int

-- >>> xs

-- index | values

-- ----- | ------

--     0 |      1

--     1 |      2

--     2 |      3

--     3 |      4

-- >>> prescanl (+) 0 xs

-- index | values

-- ----- | ------

--     0 |      0

--     1 |      1

--     2 |      3

--     3 |      6

prescanl :: (a -> b -> a) -> a -> Series k b -> Series k a
{-# INLINABLE prescanl #-}
prescanl :: forall a b k. (a -> b -> a) -> a -> Series k b -> Series k a
prescanl = (a -> b -> a) -> a -> Series Vector k b -> Series Vector k a
forall (v :: * -> *) a b k.
(Vector v a, Vector v b) =>
(a -> b -> a) -> a -> Series v k b -> Series v k a
G.prescanl


-- | Display a 'Series' using default 'DisplayOptions'.

--

-- >>> let xs = Series.fromList (zip [0..] [1,2,3,4,5,6,7]) :: Series Int Int

-- >>> putStrLn $ display xs

-- index | values

-- ----- | ------

--     0 |      1

--     1 |      2

--     2 |      3

--   ... |    ...

--     4 |      5

--     5 |      6

--     6 |      7

display :: (Show k, Show a) 
        => Series k a 
        -> String
display :: forall k a. (Show k, Show a) => Series k a -> String
display = Series Vector k a -> String
forall (v :: * -> *) a k.
(Vector v a, Show k, Show a) =>
Series v k a -> String
G.display


-- | Display a 'Series' using customizable 'DisplayOptions'.

--

-- >>> let xs = Series.fromList (zip [0..] [1,2,3,4,5,6,7]) :: Series Int Int

-- >>> import Data.List (replicate)

-- >>> :{

--     let opts = DisplayOptions { maximumNumberOfRows  = 4

--                               , indexHeader = "keys"

--                               , valuesHeader = "vals"

--                               , keyDisplayFunction   = (\i -> replicate i 'x') `noLongerThan` 5

--                               , valueDisplayFunction = (\i -> replicate i 'o') 

--                               }

--      in putStrLn $ displayWith opts xs

-- :}

--   keys |    vals

--  ----- |  ------

--        |       o

--      x |      oo

--    ... |     ...

--  xxxxx |  oooooo

-- xxx... | ooooooo

displayWith :: DisplayOptions k a
            -> Series k a 
            -> String
displayWith :: forall k a. DisplayOptions k a -> Series k a -> String
displayWith = DisplayOptions k a -> Series Vector k a -> String
forall (v :: * -> *) a k.
Vector v a =>
DisplayOptions k a -> Series v k a -> String
G.displayWith