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

module Data.MinMax3Plus where

import Prelude hiding (takeWhile,dropWhile,span)
import Data.SubG
import qualified Data.Foldable as F
import qualified Data.List as L (sortBy)

-- | Given a finite structure returns a tuple with two minimum elements
-- and three maximum elements.
-- Uses just three passes through the structure, so may be more efficient than some other approaches.
minMax23 :: (Ord a, InsertLeft t a, Monoid (t a)) => t a -> ((a,a), (a,a,a))
minMax23 :: t a -> ((a, a), (a, a, a))
minMax23 = (a -> a -> Ordering) -> t a -> ((a, a), (a, a, a))
forall a (t :: * -> *).
(Ord a, InsertLeft t a, Monoid (t a)) =>
(a -> a -> Ordering) -> t a -> ((a, a), (a, a, a))
minMax23By a -> a -> Ordering
forall a. Ord a => a -> a -> Ordering
compare
{-# INLINE minMax23 #-}

-- | A variant of the 'minMax23' where you can specify your own comparison function.
minMax23By :: (Ord a, InsertLeft t a, Monoid (t a)) => (a -> a -> Ordering) -> t a -> ((a,a), (a,a,a))
minMax23By :: (a -> a -> Ordering) -> t a -> ((a, a), (a, a, a))
minMax23By a -> a -> Ordering
g t a
xs =
  (a -> ((a, a), (a, a, a)) -> ((a, a), (a, a, a)))
-> ((a, a), (a, a, a)) -> t a -> ((a, a), (a, a, a))
forall (t :: * -> *) a b.
Foldable t =>
(a -> b -> b) -> b -> t a -> b
F.foldr a -> ((a, a), (a, a, a)) -> ((a, a), (a, a, a))
f ((a
n,a
p),(a
q,a
r,a
s)) (t a -> ((a, a), (a, a, a))) -> t a -> ((a, a), (a, a, a))
forall a b. (a -> b) -> a -> b
$ t a
str1
    where (t a
str1,t a
str2) = Integer -> t a -> (t a, t a)
forall b (t :: * -> *) a.
(Integral b, InsertLeft t a, Monoid (t a)) =>
b -> t a -> (t a, t a)
splitAtEndG Integer
5 t a
xs
          [a
n,a
p,a
q,a
r,a
s] = (a -> a -> Ordering) -> [a] -> [a]
forall a. (a -> a -> Ordering) -> [a] -> [a]
L.sortBy a -> a -> Ordering
g ([a] -> [a]) -> (t a -> [a]) -> t a -> [a]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. t a -> [a]
forall (t :: * -> *) a. Foldable t => t a -> [a]
F.toList (t a -> [a]) -> t a -> [a]
forall a b. (a -> b) -> a -> b
$ t a
str2
          f :: a -> ((a, a), (a, a, a)) -> ((a, a), (a, a, a))
f a
z ((a
x,a
y),(a
t,a
w,a
u))
            | a -> a -> Ordering
g a
z a
y Ordering -> Ordering -> Bool
forall a. Eq a => a -> a -> Bool
== Ordering
LT = if a -> a -> Ordering
g a
z a
x Ordering -> Ordering -> Bool
forall a. Eq a => a -> a -> Bool
== Ordering
GT then ((a
x,a
z),(a
t,a
w,a
u)) else ((a
z,a
x),(a
t,a
w,a
u))
            | a -> a -> Ordering
g a
z a
t Ordering -> Ordering -> Bool
forall a. Eq a => a -> a -> Bool
== Ordering
GT = if a -> a -> Ordering
g a
z a
w Ordering -> Ordering -> Bool
forall a. Eq a => a -> a -> Bool
== Ordering
LT then ((a
x,a
y),(a
z,a
w,a
u)) else if a -> a -> Ordering
g a
z a
u Ordering -> Ordering -> Bool
forall a. Eq a => a -> a -> Bool
== Ordering
LT then ((a
x,a
y),(a
w,a
z,a
u)) else ((a
x,a
y),(a
t,a
w,a
u))
            | Bool
otherwise = ((a
x,a
y),(a
t,a
w,a
u))

-- | Given a finite structure returns a tuple with three minimum elements
-- and two maximum elements. Uses just three passes through the structure, so may be more efficient than some other approaches.
minMax32 :: (Ord a, InsertLeft t a, Monoid (t a)) => t a -> ((a,a,a), (a,a))
minMax32 :: t a -> ((a, a, a), (a, a))
minMax32 = (a -> a -> Ordering) -> t a -> ((a, a, a), (a, a))
forall a (t :: * -> *).
(Ord a, InsertLeft t a, Monoid (t a)) =>
(a -> a -> Ordering) -> t a -> ((a, a, a), (a, a))
minMax32By a -> a -> Ordering
forall a. Ord a => a -> a -> Ordering
compare
{-# INLINE minMax32 #-}

-- | A variant of the 'minMax32' where you can specify your own comparison function.
minMax32By :: (Ord a, InsertLeft t a, Monoid (t a)) => (a -> a -> Ordering) -> t a -> ((a,a,a), (a,a))
minMax32By :: (a -> a -> Ordering) -> t a -> ((a, a, a), (a, a))
minMax32By a -> a -> Ordering
g t a
xs =
  (a -> ((a, a, a), (a, a)) -> ((a, a, a), (a, a)))
-> ((a, a, a), (a, a)) -> t a -> ((a, a, a), (a, a))
forall (t :: * -> *) a b.
Foldable t =>
(a -> b -> b) -> b -> t a -> b
F.foldr a -> ((a, a, a), (a, a)) -> ((a, a, a), (a, a))
f ((a
n,a
m,a
p),(a
q,a
r)) (t a -> ((a, a, a), (a, a))) -> t a -> ((a, a, a), (a, a))
forall a b. (a -> b) -> a -> b
$ t a
str1
    where (t a
str1,t a
str2) = Integer -> t a -> (t a, t a)
forall b (t :: * -> *) a.
(Integral b, InsertLeft t a, Monoid (t a)) =>
b -> t a -> (t a, t a)
splitAtEndG Integer
5 t a
xs
          [a
n,a
m,a
p,a
q,a
r] = (a -> a -> Ordering) -> [a] -> [a]
forall a. (a -> a -> Ordering) -> [a] -> [a]
L.sortBy a -> a -> Ordering
g ([a] -> [a]) -> (t a -> [a]) -> t a -> [a]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. t a -> [a]
forall (t :: * -> *) a. Foldable t => t a -> [a]
F.toList (t a -> [a]) -> t a -> [a]
forall a b. (a -> b) -> a -> b
$ t a
str2
          f :: a -> ((a, a, a), (a, a)) -> ((a, a, a), (a, a))
f a
z ((a
x,a
y,a
u),(a
t,a
w))
            | a -> a -> Ordering
g a
z a
u Ordering -> Ordering -> Bool
forall a. Eq a => a -> a -> Bool
== Ordering
LT = if a -> a -> Ordering
g a
z a
y Ordering -> Ordering -> Bool
forall a. Eq a => a -> a -> Bool
== Ordering
GT then ((a
x,a
y,a
z),(a
t,a
w)) else if a -> a -> Ordering
g a
z a
x Ordering -> Ordering -> Bool
forall a. Eq a => a -> a -> Bool
== Ordering
GT then ((a
x,a
z,a
y),(a
t,a
w)) else ((a
z,a
x,a
y),(a
t,a
w))
            | a -> a -> Ordering
g a
z a
t Ordering -> Ordering -> Bool
forall a. Eq a => a -> a -> Bool
== Ordering
GT = if a -> a -> Ordering
g a
z a
w Ordering -> Ordering -> Bool
forall a. Eq a => a -> a -> Bool
== Ordering
LT then ((a
x,a
y,a
u),(a
z,a
w)) else ((a
x,a
y,a
u),(a
w,a
z))
            | Bool
otherwise = ((a
x,a
y,a
u),(a
t,a
w))

-- | Given a finite structure returns a tuple with three minimum elements
-- and three maximum elements. Uses just three passes through the structure, so may be more efficient than some other approaches.
minMax33 :: (Ord a, InsertLeft t a, Monoid (t a)) => t a -> ((a,a,a), (a,a,a))
minMax33 :: t a -> ((a, a, a), (a, a, a))
minMax33 = (a -> a -> Ordering) -> t a -> ((a, a, a), (a, a, a))
forall a (t :: * -> *).
(Ord a, InsertLeft t a, Monoid (t a)) =>
(a -> a -> Ordering) -> t a -> ((a, a, a), (a, a, a))
minMax33By a -> a -> Ordering
forall a. Ord a => a -> a -> Ordering
compare
{-# INLINE minMax33 #-}

-- | A variant of the 'minMax33' where you can specify your own comparison function.
minMax33By :: (Ord a, InsertLeft t a, Monoid (t a)) => (a -> a -> Ordering) -> t a -> ((a,a,a), (a,a,a))
minMax33By :: (a -> a -> Ordering) -> t a -> ((a, a, a), (a, a, a))
minMax33By a -> a -> Ordering
g t a
xs =
  (a -> ((a, a, a), (a, a, a)) -> ((a, a, a), (a, a, a)))
-> ((a, a, a), (a, a, a)) -> t a -> ((a, a, a), (a, a, a))
forall (t :: * -> *) a b.
Foldable t =>
(a -> b -> b) -> b -> t a -> b
F.foldr a -> ((a, a, a), (a, a, a)) -> ((a, a, a), (a, a, a))
f ((a
n,a
m,a
p),(a
q,a
r,a
s)) (t a -> ((a, a, a), (a, a, a))) -> t a -> ((a, a, a), (a, a, a))
forall a b. (a -> b) -> a -> b
$ t a
str1
    where (t a
str1,t a
str2) = Integer -> t a -> (t a, t a)
forall b (t :: * -> *) a.
(Integral b, InsertLeft t a, Monoid (t a)) =>
b -> t a -> (t a, t a)
splitAtEndG Integer
6 t a
xs
          [a
n,a
m,a
p,a
q,a
r,a
s] = (a -> a -> Ordering) -> [a] -> [a]
forall a. (a -> a -> Ordering) -> [a] -> [a]
L.sortBy a -> a -> Ordering
g ([a] -> [a]) -> (t a -> [a]) -> t a -> [a]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. t a -> [a]
forall (t :: * -> *) a. Foldable t => t a -> [a]
F.toList (t a -> [a]) -> t a -> [a]
forall a b. (a -> b) -> a -> b
$ t a
str2
          f :: a -> ((a, a, a), (a, a, a)) -> ((a, a, a), (a, a, a))
f a
z ((a
x,a
y,a
u),(a
t,a
w,a
k))
            | a -> a -> Ordering
g a
z a
u Ordering -> Ordering -> Bool
forall a. Eq a => a -> a -> Bool
== Ordering
LT = if a -> a -> Ordering
g a
z a
y Ordering -> Ordering -> Bool
forall a. Eq a => a -> a -> Bool
== Ordering
GT then ((a
x,a
y,a
z),(a
t,a
w,a
k)) else if a -> a -> Ordering
g a
z a
x Ordering -> Ordering -> Bool
forall a. Eq a => a -> a -> Bool
== Ordering
GT then ((a
x,a
z,a
y),(a
t,a
w,a
k)) else ((a
z,a
x,a
y),(a
t,a
w,a
k))
            | a -> a -> Ordering
g a
z a
t Ordering -> Ordering -> Bool
forall a. Eq a => a -> a -> Bool
== Ordering
GT = if a -> a -> Ordering
g a
z a
w Ordering -> Ordering -> Bool
forall a. Eq a => a -> a -> Bool
== Ordering
LT then ((a
x,a
y,a
u),(a
z,a
w,a
k)) else if a -> a -> Ordering
g a
z a
k Ordering -> Ordering -> Bool
forall a. Eq a => a -> a -> Bool
== Ordering
LT then ((a
x,a
y,a
u),(a
w,a
z,a
k)) else ((a
x,a
y,a
u),(a
w,a
k,a
z))
            | Bool
otherwise = ((a
x,a
y,a
u),(a
t,a
w,a
k))