-----------------------------------------------------------------------------
-- |
-- 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