-- |
-- Module      :  Data.MinMax1
-- Copyright   :  (c) OleksandrZhabenko 2020-2024
-- License     :  MIT
-- Stability   :  Experimental
-- Maintainer  :  oleksandr.zhabenko@yahoo.com
--
-- Functions to find both minimum and maximum elements of the finite 'F.Foldable' structure of the 'Ord'ered elements.

{-# LANGUAGE NoImplicitPrelude, MultiWayIf #-}

module Data.MinMax1 where

import GHC.Base
import qualified Data.Foldable as F

-- | Returns a pair where the first element is the minimum element from the two given ones and the second one is the maximum. If the arguments are
-- equal then the tuple contains equal elements.
minmaxP :: (Ord a) => a -> a -> (a,a)
minmaxP :: forall a. Ord a => a -> a -> (a, a)
minmaxP = (a -> a -> Ordering) -> a -> a -> (a, a)
forall a. Ord a => (a -> a -> Ordering) -> a -> a -> (a, a)
minmaxPBy a -> a -> Ordering
forall a. Ord a => a -> a -> Ordering
compare
{-# INLINE minmaxP #-}

-- | A variant of the 'minmaxP' where you can specify your own comparison function.
minmaxPBy :: (Ord a) => (a -> a -> Ordering) -> a -> a -> (a,a)
minmaxPBy :: forall a. Ord a => (a -> a -> Ordering) -> a -> a -> (a, a)
minmaxPBy a -> a -> Ordering
g a
x a
y
 | a -> a -> Ordering
g a
x a
y Ordering -> Ordering -> Bool
forall a. Eq a => a -> a -> Bool
== Ordering
LT = (a
x,a
y)
 | Bool
otherwise = (a
y,a
x)

-- | A ternary predicate to check whether the third argument lies between the first two unequal ones or whether they are all equal.
betweenNX :: (Ord a) => a -> a -> a -> Bool
betweenNX :: forall a. Ord a => a -> a -> a -> Bool
betweenNX = (a -> a -> Ordering) -> a -> a -> a -> Bool
forall a. Ord a => (a -> a -> Ordering) -> a -> a -> a -> Bool
betweenNXBy a -> a -> Ordering
forall a. Ord a => a -> a -> Ordering
compare
{-# INLINE betweenNX #-}

-- | A variant of the 'betweenNX' where you can specify your own comparison function.
betweenNXBy :: (Ord a) => (a -> a -> Ordering) -> a -> a -> a -> Bool
betweenNXBy :: forall a. Ord a => (a -> a -> Ordering) -> a -> a -> a -> Bool
betweenNXBy a -> a -> Ordering
g a
x a
y a
z
 | a
x a -> a -> Bool
forall a. Eq a => a -> a -> Bool
== a
y = a
x a -> a -> Bool
forall a. Eq a => a -> a -> Bool
== a
z
 | a -> a -> Ordering
g a
z a
k Ordering -> Ordering -> Bool
forall a. Eq a => a -> a -> Bool
== Ordering
LT Bool -> Bool -> Bool
&& a -> a -> Ordering
g a
z a
t Ordering -> Ordering -> Bool
forall a. Eq a => a -> a -> Bool
== Ordering
GT = Bool
True
 | Bool
otherwise = Bool
False
      where (a
t,a
k) = (a -> a -> Ordering) -> a -> a -> (a, a)
forall a. Ord a => (a -> a -> Ordering) -> a -> a -> (a, a)
minmaxPBy a -> a -> Ordering
g a
x a
y

-- | Finds out the minimum and maximum values of the finite structure that has not less than two elements. Otherwise returns 'Nothing'.
minMax11 :: (Ord a, F.Foldable t) => t a -> Maybe (a, a)
minMax11 :: forall a (t :: * -> *). (Ord a, Foldable t) => t a -> Maybe (a, a)
minMax11 = (a -> a -> Ordering) -> t a -> Maybe (a, a)
forall a (t :: * -> *).
(Ord a, Foldable t) =>
(a -> a -> Ordering) -> t a -> Maybe (a, a)
minMax11By a -> a -> Ordering
forall a. Ord a => a -> a -> Ordering
compare
{-# INLINE minMax11 #-}
{-# SPECIALIZE minMax11 :: (Ord a) => [a] -> Maybe (a, a) #-}

-- | A generalized variant of the 'minMax11' where you can specify your own comparison function.
minMax11By :: (Ord a, F.Foldable t) => (a -> a -> Ordering) -> t a -> Maybe (a, a)
minMax11By :: forall a (t :: * -> *).
(Ord a, Foldable t) =>
(a -> a -> Ordering) -> t a -> Maybe (a, a)
minMax11By a -> a -> Ordering
g t a
xs 
 | Integer
n Integer -> Integer -> Bool
forall a. Ord a => a -> a -> Bool
< Integer
2 = Maybe (a, a)
forall a. Maybe a
Nothing
 | Bool
otherwise = (a, a) -> Maybe (a, a)
forall a. a -> Maybe a
Just (a
r1, a
r2) 
      where f :: (a, a, a) -> a -> (a, a, c)
f (a
x,a
y,a
k) a
z
              | a
k a -> a -> Bool
forall a. Ord a => a -> a -> Bool
>= a
2 = if
                 | a -> a -> Ordering
g a
z a
x Ordering -> Ordering -> Bool
forall a. Eq a => a -> a -> Bool
== Ordering
LT -> (a
z,a
y,c
2)
                 | a -> a -> Ordering
g a
z a
y Ordering -> Ordering -> Bool
forall a. Eq a => a -> a -> Bool
== Ordering
GT -> (a
x,a
z,c
2)
                 | Bool
otherwise -> (a
x,a
y,c
2)                
              | a
k a -> a -> Bool
forall a. Eq a => a -> a -> Bool
== a
1 = if
                 | a -> a -> Ordering
g a
z a
y Ordering -> Ordering -> Bool
forall a. Eq a => a -> a -> Bool
== Ordering
LT -> (a
z,a
y,c
2) 
                 | Bool
otherwise -> (a
y,a
z,c
2) 
              | Bool
otherwise = (a
forall a. HasCallStack => a
undefined,a
z,c
1)
            (a
r1,a
r2,Integer
n) = ((a, a, Integer) -> a -> (a, a, Integer))
-> (a, a, Integer) -> t a -> (a, a, Integer)
forall b a. (b -> a -> b) -> b -> t a -> b
forall (t :: * -> *) b a.
Foldable t =>
(b -> a -> b) -> b -> t a -> b
F.foldl' (a, a, Integer) -> a -> (a, a, Integer)
forall {a} {c}.
(Ord a, Num a, Num c) =>
(a, a, a) -> a -> (a, a, c)
f (a
forall a. HasCallStack => a
undefined,a
forall a. HasCallStack => a
undefined,Integer
0) t a
xs
{-# SPECIALIZE minMax11By :: (Ord a) => (a -> a -> Ordering) -> [a] -> Maybe (a, a) #-}

-- | Given a finite structure with at least 3 elements returns a tuple with the two most minimum elements
-- (the first one is less than the second one) and the maximum element. If the structure has less elements, returns 'Nothing'.
-- Uses just one pass through the structure, so may be more efficient than some other approaches.
minMax21 :: (Ord a, F.Foldable t) => t a -> Maybe (a, a, a)
minMax21 :: forall a (t :: * -> *).
(Ord a, Foldable t) =>
t a -> Maybe (a, a, a)
minMax21 = (a -> a -> Ordering) -> t a -> Maybe (a, a, a)
forall a (t :: * -> *).
(Ord a, Foldable t) =>
(a -> a -> Ordering) -> t a -> Maybe (a, a, a)
minMax21By a -> a -> Ordering
forall a. Ord a => a -> a -> Ordering
compare
{-# INLINE minMax21 #-}
{-# SPECIALIZE minMax21 :: (Ord a) => [a] -> Maybe (a,a,a) #-}

-- | A variant of the 'minMax21' where you can specify your own comparison function.
minMax21By :: (Ord a, F.Foldable t) => (a -> a -> Ordering) -> t a -> Maybe (a, a, a)
minMax21By :: forall a (t :: * -> *).
(Ord a, Foldable t) =>
(a -> a -> Ordering) -> t a -> Maybe (a, a, a)
minMax21By a -> a -> Ordering
g t a
xs
 | Integer
n Integer -> Integer -> Bool
forall a. Ord a => a -> a -> Bool
< Integer
3 = Maybe (a, a, a)
forall a. Maybe a
Nothing
 | Bool
otherwise = (a, a, a) -> Maybe (a, a, a)
forall a. a -> Maybe a
Just (a
r1, a
r2, a
r3) 
      where f :: (a, a, a, a) -> a -> (a, a, a, d)
f (a
x,a
y,a
t,a
k) a
z
              | a
k a -> a -> Bool
forall a. Ord a => a -> a -> Bool
>= a
3 = if
                 | a -> a -> Ordering
g a
z a
x Ordering -> Ordering -> Bool
forall a. Eq a => a -> a -> Bool
== Ordering
LT -> (a
z,a
x,a
t,d
3)
                 | a -> a -> Ordering
g a
z a
y Ordering -> Ordering -> Bool
forall a. Eq a => a -> a -> Bool
== Ordering
LT -> (a
x,a
z,a
t,d
3)
                 | a -> a -> Ordering
g a
z a
t Ordering -> Ordering -> Bool
forall a. Eq a => a -> a -> Bool
== Ordering
GT -> (a
x,a
y,a
z,d
3)
                 | Bool
otherwise -> (a
x,a
y,a
t,d
3)                
              | a
k a -> a -> Bool
forall a. Eq a => a -> a -> Bool
== a
2 = if
                 | a -> a -> Ordering
g a
z a
t Ordering -> Ordering -> Bool
forall a. Eq a => a -> a -> Bool
== Ordering
GT -> (a
y,a
t,a
z,d
3)
                 | a -> a -> Ordering
g a
z a
y Ordering -> Ordering -> Bool
forall a. Eq a => a -> a -> Bool
== Ordering
LT -> (a
z,a
y,a
t,d
3) 
                 | Bool
otherwise -> (a
y,a
z,a
t,d
3) 
              | a
k a -> a -> Bool
forall a. Eq a => a -> a -> Bool
== a
1 = if
                 | a -> a -> Ordering
g a
z a
t Ordering -> Ordering -> Bool
forall a. Eq a => a -> a -> Bool
== Ordering
GT -> (a
forall a. HasCallStack => a
undefined,a
t,a
z,d
2)
                 | Bool
otherwise -> (a
forall a. HasCallStack => a
undefined,a
z,a
t,d
2)
              | Bool
otherwise = (a
forall a. HasCallStack => a
undefined,a
forall a. HasCallStack => a
undefined,a
z,d
1)
            (a
r1,a
r2,a
r3,Integer
n) = ((a, a, a, Integer) -> a -> (a, a, a, Integer))
-> (a, a, a, Integer) -> t a -> (a, a, a, Integer)
forall b a. (b -> a -> b) -> b -> t a -> b
forall (t :: * -> *) b a.
Foldable t =>
(b -> a -> b) -> b -> t a -> b
F.foldl' (a, a, a, Integer) -> a -> (a, a, a, Integer)
forall {a} {d}.
(Ord a, Num a, Num d) =>
(a, a, a, a) -> a -> (a, a, a, d)
f (a
forall a. HasCallStack => a
undefined,a
forall a. HasCallStack => a
undefined,a
forall a. HasCallStack => a
undefined,Integer
0) t a
xs
{-# SPECIALIZE minMax21By :: (Ord a) => (a -> a -> Ordering) -> [a] -> Maybe (a, a, a) #-}

-- | Given a finite structure with at least 3 elements returns a tuple with the minimum element
-- and two maximum elements (the first one is less than the second one). If the structure has less elements, returns 'Nothing'.
-- Uses just one pass through the structure, so may be more efficient than some other approaches.
minMax12 :: (Ord a, F.Foldable t) => t a -> Maybe (a,a,a)
minMax12 :: forall a (t :: * -> *).
(Ord a, Foldable t) =>
t a -> Maybe (a, a, a)
minMax12 = (a -> a -> Ordering) -> t a -> Maybe (a, a, a)
forall a (t :: * -> *).
(Ord a, Foldable t) =>
(a -> a -> Ordering) -> t a -> Maybe (a, a, a)
minMax12By a -> a -> Ordering
forall a. Ord a => a -> a -> Ordering
compare
{-# INLINE minMax12 #-}
{-# SPECIALIZE minMax12 :: (Ord a) => [a] -> Maybe (a, a, a) #-}

-- | A variant of the 'minMax12' where you can specify your own comparison function.
minMax12By :: (Ord a, F.Foldable t) => (a -> a -> Ordering) -> t a -> Maybe (a,a,a)
minMax12By :: forall a (t :: * -> *).
(Ord a, Foldable t) =>
(a -> a -> Ordering) -> t a -> Maybe (a, a, a)
minMax12By a -> a -> Ordering
g t a
xs
 | Integer
n Integer -> Integer -> Bool
forall a. Ord a => a -> a -> Bool
< Integer
3 = Maybe (a, a, a)
forall a. Maybe a
Nothing
 | Bool
otherwise = (a, a, a) -> Maybe (a, a, a)
forall a. a -> Maybe a
Just (a
r1, a
r2, a
r3) 
      where f :: (a, a, a, a) -> a -> (a, a, a, d)
f (a
x,a
y,a
t,a
k) a
z
              | a
k a -> a -> Bool
forall a. Ord a => a -> a -> Bool
>= a
3 = if
                 | a -> a -> Ordering
g a
z a
x Ordering -> Ordering -> Bool
forall a. Eq a => a -> a -> Bool
== Ordering
LT -> (a
z,a
y,a
t,d
3)
                 | a -> a -> Ordering
g a
z a
t Ordering -> Ordering -> Bool
forall a. Eq a => a -> a -> Bool
== Ordering
GT -> (a
x,a
t,a
z,d
3)
                 | a -> a -> Ordering
g a
z a
y Ordering -> Ordering -> Bool
forall a. Eq a => a -> a -> Bool
== Ordering
GT -> (a
x,a
z,a
t,d
3)
                 | Bool
otherwise -> (a
x,a
y,a
t,d
3)                
              | a
k a -> a -> Bool
forall a. Eq a => a -> a -> Bool
== a
2 = if
                 | a -> a -> Ordering
g a
z a
y Ordering -> Ordering -> Bool
forall a. Eq a => a -> a -> Bool
== Ordering
LT -> (a
z,a
y,a
t,d
3)
                 | a -> a -> Ordering
g a
z a
t Ordering -> Ordering -> Bool
forall a. Eq a => a -> a -> Bool
== Ordering
GT -> (a
y,a
t,a
z,d
3) 
                 | Bool
otherwise -> (a
y,a
z,a
t,d
3) 
              | a
k a -> a -> Bool
forall a. Eq a => a -> a -> Bool
== a
1 = if
                 | a -> a -> Ordering
g a
z a
t Ordering -> Ordering -> Bool
forall a. Eq a => a -> a -> Bool
== Ordering
GT -> (a
forall a. HasCallStack => a
undefined,a
t,a
z,d
2)
                 | Bool
otherwise -> (a
forall a. HasCallStack => a
undefined,a
z,a
t,d
2)
              | Bool
otherwise = (a
forall a. HasCallStack => a
undefined,a
forall a. HasCallStack => a
undefined,a
z,d
1)
            (a
r1,a
r2,a
r3,Integer
n) = ((a, a, a, Integer) -> a -> (a, a, a, Integer))
-> (a, a, a, Integer) -> t a -> (a, a, a, Integer)
forall b a. (b -> a -> b) -> b -> t a -> b
forall (t :: * -> *) b a.
Foldable t =>
(b -> a -> b) -> b -> t a -> b
F.foldl' (a, a, a, Integer) -> a -> (a, a, a, Integer)
forall {a} {d}.
(Ord a, Num a, Num d) =>
(a, a, a, a) -> a -> (a, a, a, d)
f (a
forall a. HasCallStack => a
undefined,a
forall a. HasCallStack => a
undefined,a
forall a. HasCallStack => a
undefined,Integer
0) t a
xs
{-# SPECIALIZE  minMax12By :: (Ord a) => (a -> a -> Ordering) -> [a] -> Maybe (a,a,a) #-}

-- | Given a finite structure with at least 4 elements returns a tuple with two minimum elements
-- and two maximum elements. If the structure has less elements, returns 'Nothing'.
-- Uses just one pass through the structure, so may be more efficient than some other approaches.
minMax22 :: (Ord a, F.Foldable t) => t a -> Maybe (a,a, a,a)
minMax22 :: forall a (t :: * -> *).
(Ord a, Foldable t) =>
t a -> Maybe (a, a, a, a)
minMax22 = (a -> a -> Ordering) -> t a -> Maybe (a, a, a, a)
forall a (t :: * -> *).
(Ord a, Foldable t) =>
(a -> a -> Ordering) -> t a -> Maybe (a, a, a, a)
minMax22By a -> a -> Ordering
forall a. Ord a => a -> a -> Ordering
compare
{-# INLINE minMax22 #-}
{-# SPECIALIZE  minMax22 :: (Ord a) => [a] -> Maybe (a,a,a,a) #-}

-- | A variant of the 'minMax22' where you can specify your own comparison function.
minMax22By :: (Ord a, F.Foldable t) => (a -> a -> Ordering) -> t a -> Maybe (a,a, a,a)
minMax22By :: forall a (t :: * -> *).
(Ord a, Foldable t) =>
(a -> a -> Ordering) -> t a -> Maybe (a, a, a, a)
minMax22By a -> a -> Ordering
g t a
xs
 | Integer
n Integer -> Integer -> Bool
forall a. Ord a => a -> a -> Bool
< Integer
4 = Maybe (a, a, a, a)
forall a. Maybe a
Nothing
 | Bool
otherwise = (a, a, a, a) -> Maybe (a, a, a, a)
forall a. a -> Maybe a
Just (a
r1, a
r2, a
r3, a
r4) 
      where f :: (a, a, a, a, a) -> a -> (a, a, a, a, e)
f (a
x,a
y,a
t,a
u,a
k) a
z
              | a
k a -> a -> Bool
forall a. Ord a => a -> a -> Bool
>= a
4 = if
                 | a -> a -> Ordering
g a
z a
u Ordering -> Ordering -> Bool
forall a. Eq a => a -> a -> Bool
== Ordering
GT -> (a
x,a
y,a
u,a
z,e
4)
                 | a -> a -> Ordering
g a
z a
t Ordering -> Ordering -> Bool
forall a. Eq a => a -> a -> Bool
== Ordering
GT -> (a
x,a
y,a
z,a
u,e
4)
                 | a -> a -> Ordering
g a
z a
x Ordering -> Ordering -> Bool
forall a. Eq a => a -> a -> Bool
== Ordering
LT -> (a
z,a
x,a
t,a
u,e
4)
                 | a -> a -> Ordering
g a
z a
y Ordering -> Ordering -> Bool
forall a. Eq a => a -> a -> Bool
== Ordering
LT -> (a
x,a
z,a
t,a
u,e
4)
                 | Bool
otherwise -> (a
x,a
y,a
t,a
u,e
4)
             | a
k a -> a -> Bool
forall a. Eq a => a -> a -> Bool
== a
3 = if
                 | a -> a -> Ordering
g a
z a
u Ordering -> Ordering -> Bool
forall a. Eq a => a -> a -> Bool
== Ordering
GT -> (a
y,a
t,a
u,a
z,e
4)
                 | a -> a -> Ordering
g a
z a
t Ordering -> Ordering -> Bool
forall a. Eq a => a -> a -> Bool
== Ordering
GT -> (a
y,a
t,a
z,a
u,e
4)
                 | a -> a -> Ordering
g a
z a
y Ordering -> Ordering -> Bool
forall a. Eq a => a -> a -> Bool
== Ordering
GT -> (a
y,a
z,a
t,a
u,e
4)
                 | Bool
otherwise -> (a
z,a
y,a
t,a
u,e
4)                
              | a
k a -> a -> Bool
forall a. Eq a => a -> a -> Bool
== a
2 = if
                 | a -> a -> Ordering
g a
z a
u Ordering -> Ordering -> Bool
forall a. Eq a => a -> a -> Bool
== Ordering
GT -> (a
forall a. HasCallStack => a
undefined,a
t,a
u,a
z,e
3)
                 | a -> a -> Ordering
g a
z a
t Ordering -> Ordering -> Bool
forall a. Eq a => a -> a -> Bool
== Ordering
GT -> (a
forall a. HasCallStack => a
undefined,a
t,a
z,a
u,e
3) 
                 | Bool
otherwise -> (a
forall a. HasCallStack => a
undefined,a
z,a
t,a
u,e
3) 
              | a
k a -> a -> Bool
forall a. Eq a => a -> a -> Bool
== a
1 = if
                 | a -> a -> Ordering
g a
z a
u Ordering -> Ordering -> Bool
forall a. Eq a => a -> a -> Bool
== Ordering
GT -> (a
forall a. HasCallStack => a
undefined,a
forall a. HasCallStack => a
undefined,a
u,a
z,e
2)
                 | Bool
otherwise -> (a
forall a. HasCallStack => a
undefined,a
forall a. HasCallStack => a
undefined,a
z,a
u,e
2)
              | Bool
otherwise = (a
forall a. HasCallStack => a
undefined,a
forall a. HasCallStack => a
undefined,a
forall a. HasCallStack => a
undefined,a
z,e
1)
            (a
r1,a
r2,a
r3,a
r4,Integer
n) = ((a, a, a, a, Integer) -> a -> (a, a, a, a, Integer))
-> (a, a, a, a, Integer) -> t a -> (a, a, a, a, Integer)
forall b a. (b -> a -> b) -> b -> t a -> b
forall (t :: * -> *) b a.
Foldable t =>
(b -> a -> b) -> b -> t a -> b
F.foldl' (a, a, a, a, Integer) -> a -> (a, a, a, a, Integer)
forall {a} {e}.
(Ord a, Num a, Num e) =>
(a, a, a, a, a) -> a -> (a, a, a, a, e)
f (a
forall a. HasCallStack => a
undefined,a
forall a. HasCallStack => a
undefined,a
forall a. HasCallStack => a
undefined,a
forall a. HasCallStack => a
undefined,Integer
0) t a
xs
{-# SPECIALIZE  minMax22By :: (Ord a) => (a -> a -> Ordering) -> [a] -> Maybe (a,a,a,a) #-}