{-# LANGUAGE AllowAmbiguousTypes #-}
{-# LANGUAGE ExplicitNamespaces #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeApplications #-}
module DataFrame.Display.Internal.Common (
Agg (..),
aggLabel,
aggregateByGroup,
extractStringColumn,
extractNumericColumn,
columnToStrings,
columnToDoubles,
isNumericColumn,
isNumericColumnCheck,
getCategoricalCounts,
groupWithOther,
groupWithOtherForPie,
) where
import qualified Data.Bifunctor
import qualified Data.List as L
import qualified Data.Map.Strict as M
import qualified Data.Text as T
import Data.Type.Equality (TestEquality (testEquality), type (:~:) (Refl))
import qualified Data.Vector as V
import qualified Data.Vector.Generic as VG
import qualified Data.Vector.Unboxed as VU
import Data.Word (Word8)
import GHC.Stack (HasCallStack)
import Type.Reflection (TypeRep, typeRep)
import DataFrame.Internal.Column (
Column (..),
Columnable,
isNumeric,
materializeMerged,
materializePacked,
)
import DataFrame.Internal.DataFrame (DataFrame (..), getColumn)
import DataFrame.Internal.Types
data Agg
=
Count
|
Sum
|
Mean
|
Median
|
Min
|
Max
deriving (Agg -> Agg -> Bool
(Agg -> Agg -> Bool) -> (Agg -> Agg -> Bool) -> Eq Agg
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: Agg -> Agg -> Bool
== :: Agg -> Agg -> Bool
$c/= :: Agg -> Agg -> Bool
/= :: Agg -> Agg -> Bool
Eq, Int -> Agg -> ShowS
[Agg] -> ShowS
Agg -> String
(Int -> Agg -> ShowS)
-> (Agg -> String) -> ([Agg] -> ShowS) -> Show Agg
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> Agg -> ShowS
showsPrec :: Int -> Agg -> ShowS
$cshow :: Agg -> String
show :: Agg -> String
$cshowList :: [Agg] -> ShowS
showList :: [Agg] -> ShowS
Show)
aggLabel :: Agg -> T.Text
aggLabel :: Agg -> Text
aggLabel Agg
Count = Text
"count"
aggLabel Agg
Sum = Text
"sum"
aggLabel Agg
Mean = Text
"mean"
aggLabel Agg
Median = Text
"median"
aggLabel Agg
Min = Text
"min"
aggLabel Agg
Max = Text
"max"
aggregateByGroup ::
(HasCallStack) =>
Agg ->
T.Text ->
Maybe T.Text ->
DataFrame ->
[(T.Text, Double)]
aggregateByGroup :: HasCallStack =>
Agg -> Text -> Maybe Text -> DataFrame -> [(Text, Double)]
aggregateByGroup Agg
Count Text
groupCol Maybe Text
_ DataFrame
df =
let groups :: [Text]
groups = HasCallStack => Text -> DataFrame -> [Text]
Text -> DataFrame -> [Text]
extractStringColumn Text
groupCol DataFrame
df
m :: Map Text Double
m = (Map Text Double -> Text -> Map Text Double)
-> Map Text Double -> [Text] -> Map Text Double
forall b a. (b -> a -> b) -> b -> [a] -> b
forall (t :: * -> *) b a.
Foldable t =>
(b -> a -> b) -> b -> t a -> b
L.foldl' (\Map Text Double
acc Text
g -> (Double -> Double -> Double)
-> Text -> Double -> Map Text Double -> Map Text Double
forall k a. Ord k => (a -> a -> a) -> k -> a -> Map k a -> Map k a
M.insertWith Double -> Double -> Double
forall a. Num a => a -> a -> a
(+) Text
g Double
1 Map Text Double
acc) Map Text Double
forall k a. Map k a
M.empty [Text]
groups
seen :: [Text]
seen = [Text] -> [Text]
forall a. Eq a => [a] -> [a]
L.nub [Text]
groups
in [(Text
g, Double -> Text -> Map Text Double -> Double
forall k a. Ord k => a -> k -> Map k a -> a
M.findWithDefault Double
0 Text
g Map Text Double
m) | Text
g <- [Text]
seen]
aggregateByGroup Agg
agg Text
groupCol Maybe Text
mValueCol DataFrame
df = case Maybe Text
mValueCol of
Maybe Text
Nothing ->
String -> [(Text, Double)]
forall a. HasCallStack => String -> a
error (String -> [(Text, Double)]) -> String -> [(Text, Double)]
forall a b. (a -> b) -> a -> b
$
String
"Aggregation "
String -> ShowS
forall a. [a] -> [a] -> [a]
++ Agg -> String
forall a. Show a => a -> String
show Agg
agg
String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
" requires a value column; only Count works without one."
Just Text
valueCol ->
let groups :: [Text]
groups = HasCallStack => Text -> DataFrame -> [Text]
Text -> DataFrame -> [Text]
extractStringColumn Text
groupCol DataFrame
df
values :: [Double]
values = HasCallStack => Text -> DataFrame -> [Double]
Text -> DataFrame -> [Double]
extractNumericColumn Text
valueCol DataFrame
df
seen :: [Text]
seen = [Text] -> [Text]
forall a. Eq a => [a] -> [a]
L.nub [Text]
groups
pairs :: [(Text, Double)]
pairs = [Text] -> [Double] -> [(Text, Double)]
forall a b. [a] -> [b] -> [(a, b)]
zip [Text]
groups [Double]
values
byGroup :: Map Text [Double]
byGroup =
(Map Text [Double] -> (Text, Double) -> Map Text [Double])
-> Map Text [Double] -> [(Text, Double)] -> Map Text [Double]
forall b a. (b -> a -> b) -> b -> [a] -> b
forall (t :: * -> *) b a.
Foldable t =>
(b -> a -> b) -> b -> t a -> b
L.foldl'
(\Map Text [Double]
acc (Text
g, Double
v) -> ([Double] -> [Double] -> [Double])
-> Text -> [Double] -> Map Text [Double] -> Map Text [Double]
forall k a. Ord k => (a -> a -> a) -> k -> a -> Map k a -> Map k a
M.insertWith (([Double] -> [Double] -> [Double])
-> [Double] -> [Double] -> [Double]
forall a b c. (a -> b -> c) -> b -> a -> c
flip [Double] -> [Double] -> [Double]
forall a. [a] -> [a] -> [a]
(++)) Text
g [Double
v] Map Text [Double]
acc)
Map Text [Double]
forall k a. Map k a
M.empty
[(Text, Double)]
pairs
reduce :: [Double] -> Double
reduce = Agg -> [Double] -> Double
numericReducer Agg
agg
in [(Text
g, [Double] -> Double
reduce ([Double] -> Text -> Map Text [Double] -> [Double]
forall k a. Ord k => a -> k -> Map k a -> a
M.findWithDefault [] Text
g Map Text [Double]
byGroup)) | Text
g <- [Text]
seen]
numericReducer :: Agg -> [Double] -> Double
numericReducer :: Agg -> [Double] -> Double
numericReducer Agg
Sum = [Double] -> Double
forall a. Num a => [a] -> a
forall (t :: * -> *) a. (Foldable t, Num a) => t a -> a
sum
numericReducer Agg
Mean = \[Double]
vs -> if [Double] -> Bool
forall a. [a] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null [Double]
vs then Double
0 else [Double] -> Double
forall a. Num a => [a] -> a
forall (t :: * -> *) a. (Foldable t, Num a) => t a -> a
sum [Double]
vs Double -> Double -> Double
forall a. Fractional a => a -> a -> a
/ Int -> Double
forall a b. (Integral a, Num b) => a -> b
fromIntegral ([Double] -> Int
forall a. [a] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length [Double]
vs)
numericReducer Agg
Median = [Double] -> Double
medianD
numericReducer Agg
Min = [Double] -> Double
forall a. Ord a => [a] -> a
forall (t :: * -> *) a. (Foldable t, Ord a) => t a -> a
minimum
numericReducer Agg
Max = [Double] -> Double
forall a. Ord a => [a] -> a
forall (t :: * -> *) a. (Foldable t, Ord a) => t a -> a
maximum
numericReducer Agg
Count = Int -> Double
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Int -> Double) -> ([Double] -> Int) -> [Double] -> Double
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [Double] -> Int
forall a. [a] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length
medianD :: [Double] -> Double
medianD :: [Double] -> Double
medianD [] = Double
0
medianD [Double]
xs =
let sorted :: [Double]
sorted = [Double] -> [Double]
forall a. Ord a => [a] -> [a]
L.sort [Double]
xs
n :: Int
n = [Double] -> Int
forall a. [a] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length [Double]
sorted
mid :: Int
mid = Int
n Int -> Int -> Int
forall a. Integral a => a -> a -> a
`div` Int
2
in if Int -> Bool
forall a. Integral a => a -> Bool
even Int
n
then ([Double]
sorted [Double] -> Int -> Double
forall a. HasCallStack => [a] -> Int -> a
!! (Int
mid Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
1) Double -> Double -> Double
forall a. Num a => a -> a -> a
+ [Double]
sorted [Double] -> Int -> Double
forall a. HasCallStack => [a] -> Int -> a
!! Int
mid) Double -> Double -> Double
forall a. Fractional a => a -> a -> a
/ Double
2
else [Double]
sorted [Double] -> Int -> Double
forall a. HasCallStack => [a] -> Int -> a
!! Int
mid
isNumericColumn :: DataFrame -> T.Text -> Bool
isNumericColumn :: DataFrame -> Text -> Bool
isNumericColumn DataFrame
df Text
colName = Bool -> (Column -> Bool) -> Maybe Column -> Bool
forall b a. b -> (a -> b) -> Maybe a -> b
maybe Bool
False Column -> Bool
isNumeric (Text -> DataFrame -> Maybe Column
getColumn Text
colName DataFrame
df)
isNumericColumnCheck :: T.Text -> DataFrame -> Bool
isNumericColumnCheck :: Text -> DataFrame -> Bool
isNumericColumnCheck Text
colName DataFrame
df = DataFrame -> Text -> Bool
isNumericColumn DataFrame
df Text
colName
extractStringColumn :: (HasCallStack) => T.Text -> DataFrame -> [T.Text]
extractStringColumn :: HasCallStack => Text -> DataFrame -> [Text]
extractStringColumn Text
colName DataFrame
df =
case Text -> Map Text Int -> Maybe Int
forall k a. Ord k => k -> Map k a -> Maybe a
M.lookup Text
colName (DataFrame -> Map Text Int
columnIndices DataFrame
df) of
Maybe Int
Nothing -> String -> [Text]
forall a. HasCallStack => String -> a
error (String -> [Text]) -> String -> [Text]
forall a b. (a -> b) -> a -> b
$ String
"Column " String -> ShowS
forall a. [a] -> [a] -> [a]
++ Text -> String
T.unpack Text
colName String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
" not found"
Just Int
idx -> HasCallStack => Column -> [Text]
Column -> [Text]
columnToStrings (DataFrame -> Vector Column
columns DataFrame
df Vector Column -> Int -> Column
forall a. Vector a -> Int -> a
V.! Int
idx)
extractNumericColumn :: (HasCallStack) => T.Text -> DataFrame -> [Double]
extractNumericColumn :: HasCallStack => Text -> DataFrame -> [Double]
extractNumericColumn Text
colName DataFrame
df =
case Text -> Map Text Int -> Maybe Int
forall k a. Ord k => k -> Map k a -> Maybe a
M.lookup Text
colName (DataFrame -> Map Text Int
columnIndices DataFrame
df) of
Maybe Int
Nothing -> String -> [Double]
forall a. HasCallStack => String -> a
error (String -> [Double]) -> String -> [Double]
forall a b. (a -> b) -> a -> b
$ String
"Column " String -> ShowS
forall a. [a] -> [a] -> [a]
++ Text -> String
T.unpack Text
colName String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
" not found"
Just Int
idx -> HasCallStack => Column -> [Double]
Column -> [Double]
columnToDoubles (DataFrame -> Vector Column
columns DataFrame
df Vector Column -> Int -> Column
forall a. Vector a -> Int -> a
V.! Int
idx)
columnToStrings :: (HasCallStack) => Column -> [T.Text]
columnToStrings :: HasCallStack => Column -> [Text]
columnToStrings Column
col = case Column
col of
BoxedColumn Maybe Bitmap
_ (Vector a
vec :: V.Vector a) ->
case TypeRep a -> TypeRep Text -> Maybe (a :~: Text)
forall a b. TypeRep a -> TypeRep b -> Maybe (a :~: b)
forall {k} (f :: k -> *) (a :: k) (b :: k).
TestEquality f =>
f a -> f b -> Maybe (a :~: b)
testEquality (forall a. Typeable a => TypeRep a
forall {k} (a :: k). Typeable a => TypeRep a
typeRep @a) (forall a. Typeable a => TypeRep a
forall {k} (a :: k). Typeable a => TypeRep a
typeRep @T.Text) of
Just a :~: Text
Refl -> Vector Text -> [Text]
forall a. Vector a -> [a]
V.toList Vector a
Vector Text
vec
Maybe (a :~: Text)
Nothing -> Vector Text -> [Text]
forall a. Vector a -> [a]
V.toList (Vector Text -> [Text]) -> Vector Text -> [Text]
forall a b. (a -> b) -> a -> b
$ (a -> Text) -> Vector a -> Vector Text
forall a b. (a -> b) -> Vector a -> Vector b
V.map (String -> Text
T.pack (String -> Text) -> (a -> String) -> a -> Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. a -> String
forall a. Show a => a -> String
show) Vector a
vec
UnboxedColumn Maybe Bitmap
_ Vector a
vec ->
Vector Text -> [Text]
forall a. Vector a -> [a]
V.toList (Vector Text -> [Text]) -> Vector Text -> [Text]
forall a b. (a -> b) -> a -> b
$ (a -> Text) -> Vector a -> Vector Text
forall (v :: * -> *) a b.
(Vector v a, Vector v b) =>
(a -> b) -> v a -> v b
VG.map (String -> Text
T.pack (String -> Text) -> (a -> String) -> a -> Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. a -> String
forall a. Show a => a -> String
show) (Vector a -> Vector a
forall (v :: * -> *) a (w :: * -> *).
(Vector v a, Vector w a) =>
v a -> w a
VG.convert Vector a
vec)
PackedText Maybe Bitmap
_ PackedTextData
_ -> HasCallStack => Column -> [Text]
Column -> [Text]
columnToStrings (Column -> Column
materializePacked Column
col)
MergedColumn Column
_ Column
_ -> HasCallStack => Column -> [Text]
Column -> [Text]
columnToStrings (Column -> Column
materializeMerged Column
col)
columnToDoubles :: (HasCallStack) => Column -> [Double]
columnToDoubles :: HasCallStack => Column -> [Double]
columnToDoubles Column
col = case Column
col of
BoxedColumn Maybe Bitmap
_ Vector a
vec -> Vector a -> [Double]
forall a. (Columnable a, Show a) => Vector a -> [Double]
vectorToDoubles Vector a
vec
UnboxedColumn Maybe Bitmap
_ Vector a
vec -> Vector a -> [Double]
forall a. (Columnable a, Unbox a, Show a) => Vector a -> [Double]
unboxedVectorToDoubles Vector a
vec
PackedText Maybe Bitmap
_ PackedTextData
_ -> HasCallStack => Column -> [Double]
Column -> [Double]
columnToDoubles (Column -> Column
materializePacked Column
col)
MergedColumn Column
_ Column
_ -> HasCallStack => Column -> [Double]
Column -> [Double]
columnToDoubles (Column -> Column
materializeMerged Column
col)
vectorToDoubles :: forall a. (Columnable a, Show a) => V.Vector a -> [Double]
vectorToDoubles :: forall a. (Columnable a, Show a) => Vector a -> [Double]
vectorToDoubles Vector a
vec =
case TypeRep a -> TypeRep Double -> Maybe (a :~: Double)
forall a b. TypeRep a -> TypeRep b -> Maybe (a :~: b)
forall {k} (f :: k -> *) (a :: k) (b :: k).
TestEquality f =>
f a -> f b -> Maybe (a :~: b)
testEquality (forall a. Typeable a => TypeRep a
forall {k} (a :: k). Typeable a => TypeRep a
typeRep @a) (forall a. Typeable a => TypeRep a
forall {k} (a :: k). Typeable a => TypeRep a
typeRep @Double) of
Just a :~: Double
Refl -> Vector Double -> [Double]
forall a. Vector a -> [a]
V.toList Vector a
Vector Double
vec
Maybe (a :~: Double)
Nothing -> case forall a. SBoolI (IntegralTypes a) => SBool (IntegralTypes a)
sIntegral @a of
SBool (IntegralTypes a)
STrue -> Vector Double -> [Double]
forall a. Vector a -> [a]
V.toList (Vector Double -> [Double]) -> Vector Double -> [Double]
forall a b. (a -> b) -> a -> b
$ (a -> Double) -> Vector a -> Vector Double
forall a b. (a -> b) -> Vector a -> Vector b
V.map a -> Double
forall a b. (Integral a, Num b) => a -> b
fromIntegral Vector a
vec
SBool (IntegralTypes a)
SFalse -> case forall a. SBoolI (FloatingTypes a) => SBool (FloatingTypes a)
sFloating @a of
SBool (FloatingTypes a)
STrue -> Vector Double -> [Double]
forall a. Vector a -> [a]
V.toList (Vector Double -> [Double]) -> Vector Double -> [Double]
forall a b. (a -> b) -> a -> b
$ (a -> Double) -> Vector a -> Vector Double
forall a b. (a -> b) -> Vector a -> Vector b
V.map a -> Double
forall a b. (Real a, Fractional b) => a -> b
realToFrac Vector a
vec
SBool (FloatingTypes a)
SFalse ->
String -> [Double]
forall a. HasCallStack => String -> a
error (String -> [Double]) -> String -> [Double]
forall a b. (a -> b) -> a -> b
$ String
"Column is not numeric (type: " String -> ShowS
forall a. [a] -> [a] -> [a]
++ TypeRep a -> String
forall a. Show a => a -> String
show (forall a. Typeable a => TypeRep a
forall {k} (a :: k). Typeable a => TypeRep a
typeRep @a) String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
")"
unboxedVectorToDoubles ::
forall a. (Columnable a, VU.Unbox a, Show a) => VU.Vector a -> [Double]
unboxedVectorToDoubles :: forall a. (Columnable a, Unbox a, Show a) => Vector a -> [Double]
unboxedVectorToDoubles Vector a
vec =
case TypeRep a -> TypeRep Double -> Maybe (a :~: Double)
forall a b. TypeRep a -> TypeRep b -> Maybe (a :~: b)
forall {k} (f :: k -> *) (a :: k) (b :: k).
TestEquality f =>
f a -> f b -> Maybe (a :~: b)
testEquality (forall a. Typeable a => TypeRep a
forall {k} (a :: k). Typeable a => TypeRep a
typeRep @a) (forall a. Typeable a => TypeRep a
forall {k} (a :: k). Typeable a => TypeRep a
typeRep @Double) of
Just a :~: Double
Refl -> Vector Double -> [Double]
forall a. Unbox a => Vector a -> [a]
VU.toList Vector a
Vector Double
vec
Maybe (a :~: Double)
Nothing -> case forall a. SBoolI (IntegralTypes a) => SBool (IntegralTypes a)
sIntegral @a of
SBool (IntegralTypes a)
STrue -> Vector Double -> [Double]
forall a. Unbox a => Vector a -> [a]
VU.toList (Vector Double -> [Double]) -> Vector Double -> [Double]
forall a b. (a -> b) -> a -> b
$ (a -> Double) -> Vector a -> Vector Double
forall a b. (Unbox a, Unbox b) => (a -> b) -> Vector a -> Vector b
VU.map a -> Double
forall a b. (Integral a, Num b) => a -> b
fromIntegral Vector a
vec
SBool (IntegralTypes a)
SFalse -> case forall a. SBoolI (FloatingTypes a) => SBool (FloatingTypes a)
sFloating @a of
SBool (FloatingTypes a)
STrue -> Vector Double -> [Double]
forall a. Unbox a => Vector a -> [a]
VU.toList (Vector Double -> [Double]) -> Vector Double -> [Double]
forall a b. (a -> b) -> a -> b
$ (a -> Double) -> Vector a -> Vector Double
forall a b. (Unbox a, Unbox b) => (a -> b) -> Vector a -> Vector b
VU.map a -> Double
forall a b. (Real a, Fractional b) => a -> b
realToFrac Vector a
vec
SBool (FloatingTypes a)
SFalse ->
String -> [Double]
forall a. HasCallStack => String -> a
error (String -> [Double]) -> String -> [Double]
forall a b. (a -> b) -> a -> b
$ String
"Column is not numeric (type: " String -> ShowS
forall a. [a] -> [a] -> [a]
++ TypeRep a -> String
forall a. Show a => a -> String
show (forall a. Typeable a => TypeRep a
forall {k} (a :: k). Typeable a => TypeRep a
typeRep @a) String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
")"
getCategoricalCounts ::
(HasCallStack) => T.Text -> DataFrame -> Maybe [(T.Text, Double)]
getCategoricalCounts :: HasCallStack => Text -> DataFrame -> Maybe [(Text, Double)]
getCategoricalCounts Text
colName DataFrame
df =
case Text -> Map Text Int -> Maybe Int
forall k a. Ord k => k -> Map k a -> Maybe a
M.lookup Text
colName (DataFrame -> Map Text Int
columnIndices DataFrame
df) of
Maybe Int
Nothing -> String -> Maybe [(Text, Double)]
forall a. HasCallStack => String -> a
error (String -> Maybe [(Text, Double)])
-> String -> Maybe [(Text, Double)]
forall a b. (a -> b) -> a -> b
$ String
"Column " String -> ShowS
forall a. [a] -> [a] -> [a]
++ Text -> String
T.unpack Text
colName String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
" not found"
Just Int
idx ->
let col :: Column
col = DataFrame -> Vector Column
columns DataFrame
df Vector Column -> Int -> Column
forall a. Vector a -> Int -> a
V.! Int
idx
in case Column
col of
BoxedColumn Maybe Bitmap
_ (Vector a
vec :: V.Vector a) ->
[(Text, Double)] -> Maybe [(Text, Double)]
forall a. a -> Maybe a
Just (TypeRep a -> Vector a -> [(Text, Double)]
forall a. Show a => TypeRep a -> Vector a -> [(Text, Double)]
countBoxed (forall a. Typeable a => TypeRep a
forall {k} (a :: k). Typeable a => TypeRep a
typeRep @a) Vector a
vec)
UnboxedColumn Maybe Bitmap
_ (Vector a
vec :: VU.Vector a) ->
[(Text, Double)] -> Maybe [(Text, Double)]
forall a. a -> Maybe a
Just (TypeRep a -> Vector a -> [(Text, Double)]
forall a.
(Show a, Unbox a) =>
TypeRep a -> Vector a -> [(Text, Double)]
countUnboxed (forall a. Typeable a => TypeRep a
forall {k} (a :: k). Typeable a => TypeRep a
typeRep @a) Vector a
vec)
PackedText Maybe Bitmap
_ PackedTextData
_ -> case Column -> Column
materializePacked Column
col of
BoxedColumn Maybe Bitmap
_ (Vector a
vec :: V.Vector a) -> [(Text, Double)] -> Maybe [(Text, Double)]
forall a. a -> Maybe a
Just (TypeRep a -> Vector a -> [(Text, Double)]
forall a. Show a => TypeRep a -> Vector a -> [(Text, Double)]
countBoxed (forall a. Typeable a => TypeRep a
forall {k} (a :: k). Typeable a => TypeRep a
typeRep @a) Vector a
vec)
Column
_ -> Maybe [(Text, Double)]
forall a. Maybe a
Nothing
MergedColumn Column
_ Column
_ -> case Column -> Column
materializeMerged Column
col of
BoxedColumn Maybe Bitmap
_ (Vector a
vec :: V.Vector a) -> [(Text, Double)] -> Maybe [(Text, Double)]
forall a. a -> Maybe a
Just (TypeRep a -> Vector a -> [(Text, Double)]
forall a. Show a => TypeRep a -> Vector a -> [(Text, Double)]
countBoxed (forall a. Typeable a => TypeRep a
forall {k} (a :: k). Typeable a => TypeRep a
typeRep @a) Vector a
vec)
Column
_ -> Maybe [(Text, Double)]
forall a. Maybe a
Nothing
where
countBoxed ::
forall a. (Show a) => TypeRep a -> V.Vector a -> [(T.Text, Double)]
countBoxed :: forall a. Show a => TypeRep a -> Vector a -> [(Text, Double)]
countBoxed TypeRep a
tr Vector a
vec
| Just a :~: Text
Refl <- TypeRep a -> TypeRep Text -> Maybe (a :~: Text)
forall a b. TypeRep a -> TypeRep b -> Maybe (a :~: b)
forall {k} (f :: k -> *) (a :: k) (b :: k).
TestEquality f =>
f a -> f b -> Maybe (a :~: b)
testEquality TypeRep a
tr (forall a. Typeable a => TypeRep a
forall {k} (a :: k). Typeable a => TypeRep a
typeRep @T.Text) = [(Text, Int)] -> [(Text, Double)]
toPairsText ([(Text, Int)] -> [(Text, Double)])
-> [(Text, Int)] -> [(Text, Double)]
forall a b. (a -> b) -> a -> b
$ Vector Text -> [(Text, Int)]
forall a. Ord a => Vector a -> [(a, Int)]
countValues Vector a
Vector Text
vec
| Just a :~: String
Refl <- TypeRep a -> TypeRep String -> Maybe (a :~: String)
forall a b. TypeRep a -> TypeRep b -> Maybe (a :~: b)
forall {k} (f :: k -> *) (a :: k) (b :: k).
TestEquality f =>
f a -> f b -> Maybe (a :~: b)
testEquality TypeRep a
tr (forall a. Typeable a => TypeRep a
forall {k} (a :: k). Typeable a => TypeRep a
typeRep @String) = [(a, Int)] -> [(Text, Double)]
forall a. Show a => [(a, Int)] -> [(Text, Double)]
toPairs ([(a, Int)] -> [(Text, Double)]) -> [(a, Int)] -> [(Text, Double)]
forall a b. (a -> b) -> a -> b
$ Vector a -> [(a, Int)]
forall a. Ord a => Vector a -> [(a, Int)]
countValues Vector a
vec
| Just a :~: Integer
Refl <- TypeRep a -> TypeRep Integer -> Maybe (a :~: Integer)
forall a b. TypeRep a -> TypeRep b -> Maybe (a :~: b)
forall {k} (f :: k -> *) (a :: k) (b :: k).
TestEquality f =>
f a -> f b -> Maybe (a :~: b)
testEquality TypeRep a
tr (forall a. Typeable a => TypeRep a
forall {k} (a :: k). Typeable a => TypeRep a
typeRep @Integer) = [(a, Int)] -> [(Text, Double)]
forall a. Show a => [(a, Int)] -> [(Text, Double)]
toPairs ([(a, Int)] -> [(Text, Double)]) -> [(a, Int)] -> [(Text, Double)]
forall a b. (a -> b) -> a -> b
$ Vector a -> [(a, Int)]
forall a. Ord a => Vector a -> [(a, Int)]
countValues Vector a
vec
| Just a :~: Int
Refl <- TypeRep a -> TypeRep Int -> Maybe (a :~: Int)
forall a b. TypeRep a -> TypeRep b -> Maybe (a :~: b)
forall {k} (f :: k -> *) (a :: k) (b :: k).
TestEquality f =>
f a -> f b -> Maybe (a :~: b)
testEquality TypeRep a
tr (forall a. Typeable a => TypeRep a
forall {k} (a :: k). Typeable a => TypeRep a
typeRep @Int) = [(a, Int)] -> [(Text, Double)]
forall a. Show a => [(a, Int)] -> [(Text, Double)]
toPairs ([(a, Int)] -> [(Text, Double)]) -> [(a, Int)] -> [(Text, Double)]
forall a b. (a -> b) -> a -> b
$ Vector a -> [(a, Int)]
forall a. Ord a => Vector a -> [(a, Int)]
countValues Vector a
vec
| Just a :~: Double
Refl <- TypeRep a -> TypeRep Double -> Maybe (a :~: Double)
forall a b. TypeRep a -> TypeRep b -> Maybe (a :~: b)
forall {k} (f :: k -> *) (a :: k) (b :: k).
TestEquality f =>
f a -> f b -> Maybe (a :~: b)
testEquality TypeRep a
tr (forall a. Typeable a => TypeRep a
forall {k} (a :: k). Typeable a => TypeRep a
typeRep @Double) = [(a, Int)] -> [(Text, Double)]
forall a. Show a => [(a, Int)] -> [(Text, Double)]
toPairs ([(a, Int)] -> [(Text, Double)]) -> [(a, Int)] -> [(Text, Double)]
forall a b. (a -> b) -> a -> b
$ Vector a -> [(a, Int)]
forall a. Ord a => Vector a -> [(a, Int)]
countValues Vector a
vec
| Just a :~: Float
Refl <- TypeRep a -> TypeRep Float -> Maybe (a :~: Float)
forall a b. TypeRep a -> TypeRep b -> Maybe (a :~: b)
forall {k} (f :: k -> *) (a :: k) (b :: k).
TestEquality f =>
f a -> f b -> Maybe (a :~: b)
testEquality TypeRep a
tr (forall a. Typeable a => TypeRep a
forall {k} (a :: k). Typeable a => TypeRep a
typeRep @Float) = [(a, Int)] -> [(Text, Double)]
forall a. Show a => [(a, Int)] -> [(Text, Double)]
toPairs ([(a, Int)] -> [(Text, Double)]) -> [(a, Int)] -> [(Text, Double)]
forall a b. (a -> b) -> a -> b
$ Vector a -> [(a, Int)]
forall a. Ord a => Vector a -> [(a, Int)]
countValues Vector a
vec
| Just a :~: Bool
Refl <- TypeRep a -> TypeRep Bool -> Maybe (a :~: Bool)
forall a b. TypeRep a -> TypeRep b -> Maybe (a :~: b)
forall {k} (f :: k -> *) (a :: k) (b :: k).
TestEquality f =>
f a -> f b -> Maybe (a :~: b)
testEquality TypeRep a
tr (forall a. Typeable a => TypeRep a
forall {k} (a :: k). Typeable a => TypeRep a
typeRep @Bool) = [(a, Int)] -> [(Text, Double)]
forall a. Show a => [(a, Int)] -> [(Text, Double)]
toPairs ([(a, Int)] -> [(Text, Double)]) -> [(a, Int)] -> [(Text, Double)]
forall a b. (a -> b) -> a -> b
$ Vector a -> [(a, Int)]
forall a. Ord a => Vector a -> [(a, Int)]
countValues Vector a
vec
| Just a :~: Char
Refl <- TypeRep a -> TypeRep Char -> Maybe (a :~: Char)
forall a b. TypeRep a -> TypeRep b -> Maybe (a :~: b)
forall {k} (f :: k -> *) (a :: k) (b :: k).
TestEquality f =>
f a -> f b -> Maybe (a :~: b)
testEquality TypeRep a
tr (forall a. Typeable a => TypeRep a
forall {k} (a :: k). Typeable a => TypeRep a
typeRep @Char) = [(a, Int)] -> [(Text, Double)]
forall a. Show a => [(a, Int)] -> [(Text, Double)]
toPairs ([(a, Int)] -> [(Text, Double)]) -> [(a, Int)] -> [(Text, Double)]
forall a b. (a -> b) -> a -> b
$ Vector a -> [(a, Int)]
forall a. Ord a => Vector a -> [(a, Int)]
countValues Vector a
vec
| Bool
otherwise = [a] -> [(Text, Double)]
forall a. Show a => [a] -> [(Text, Double)]
countByShow ([a] -> [(Text, Double)]) -> [a] -> [(Text, Double)]
forall a b. (a -> b) -> a -> b
$ Vector a -> [a]
forall a. Vector a -> [a]
V.toList Vector a
vec
countUnboxed ::
forall a. (Show a, VU.Unbox a) => TypeRep a -> VU.Vector a -> [(T.Text, Double)]
countUnboxed :: forall a.
(Show a, Unbox a) =>
TypeRep a -> Vector a -> [(Text, Double)]
countUnboxed TypeRep a
tr Vector a
vec
| Just a :~: Int
Refl <- TypeRep a -> TypeRep Int -> Maybe (a :~: Int)
forall a b. TypeRep a -> TypeRep b -> Maybe (a :~: b)
forall {k} (f :: k -> *) (a :: k) (b :: k).
TestEquality f =>
f a -> f b -> Maybe (a :~: b)
testEquality TypeRep a
tr (forall a. Typeable a => TypeRep a
forall {k} (a :: k). Typeable a => TypeRep a
typeRep @Int) = [(a, Int)] -> [(Text, Double)]
forall a. Show a => [(a, Int)] -> [(Text, Double)]
toPairs ([(a, Int)] -> [(Text, Double)]) -> [(a, Int)] -> [(Text, Double)]
forall a b. (a -> b) -> a -> b
$ Vector a -> [(a, Int)]
forall a. (Ord a, Unbox a) => Vector a -> [(a, Int)]
countValuesUnboxed Vector a
vec
| Just a :~: Double
Refl <- TypeRep a -> TypeRep Double -> Maybe (a :~: Double)
forall a b. TypeRep a -> TypeRep b -> Maybe (a :~: b)
forall {k} (f :: k -> *) (a :: k) (b :: k).
TestEquality f =>
f a -> f b -> Maybe (a :~: b)
testEquality TypeRep a
tr (forall a. Typeable a => TypeRep a
forall {k} (a :: k). Typeable a => TypeRep a
typeRep @Double) =
[(a, Int)] -> [(Text, Double)]
forall a. Show a => [(a, Int)] -> [(Text, Double)]
toPairs ([(a, Int)] -> [(Text, Double)]) -> [(a, Int)] -> [(Text, Double)]
forall a b. (a -> b) -> a -> b
$ Vector a -> [(a, Int)]
forall a. (Ord a, Unbox a) => Vector a -> [(a, Int)]
countValuesUnboxed Vector a
vec
| Just a :~: Float
Refl <- TypeRep a -> TypeRep Float -> Maybe (a :~: Float)
forall a b. TypeRep a -> TypeRep b -> Maybe (a :~: b)
forall {k} (f :: k -> *) (a :: k) (b :: k).
TestEquality f =>
f a -> f b -> Maybe (a :~: b)
testEquality TypeRep a
tr (forall a. Typeable a => TypeRep a
forall {k} (a :: k). Typeable a => TypeRep a
typeRep @Float) =
[(a, Int)] -> [(Text, Double)]
forall a. Show a => [(a, Int)] -> [(Text, Double)]
toPairs ([(a, Int)] -> [(Text, Double)]) -> [(a, Int)] -> [(Text, Double)]
forall a b. (a -> b) -> a -> b
$ Vector a -> [(a, Int)]
forall a. (Ord a, Unbox a) => Vector a -> [(a, Int)]
countValuesUnboxed Vector a
vec
| Just a :~: Bool
Refl <- TypeRep a -> TypeRep Bool -> Maybe (a :~: Bool)
forall a b. TypeRep a -> TypeRep b -> Maybe (a :~: b)
forall {k} (f :: k -> *) (a :: k) (b :: k).
TestEquality f =>
f a -> f b -> Maybe (a :~: b)
testEquality TypeRep a
tr (forall a. Typeable a => TypeRep a
forall {k} (a :: k). Typeable a => TypeRep a
typeRep @Bool) =
[(a, Int)] -> [(Text, Double)]
forall a. Show a => [(a, Int)] -> [(Text, Double)]
toPairs ([(a, Int)] -> [(Text, Double)]) -> [(a, Int)] -> [(Text, Double)]
forall a b. (a -> b) -> a -> b
$ Vector a -> [(a, Int)]
forall a. (Ord a, Unbox a) => Vector a -> [(a, Int)]
countValuesUnboxed Vector a
vec
| Just a :~: Char
Refl <- TypeRep a -> TypeRep Char -> Maybe (a :~: Char)
forall a b. TypeRep a -> TypeRep b -> Maybe (a :~: b)
forall {k} (f :: k -> *) (a :: k) (b :: k).
TestEquality f =>
f a -> f b -> Maybe (a :~: b)
testEquality TypeRep a
tr (forall a. Typeable a => TypeRep a
forall {k} (a :: k). Typeable a => TypeRep a
typeRep @Char) =
[(a, Int)] -> [(Text, Double)]
forall a. Show a => [(a, Int)] -> [(Text, Double)]
toPairs ([(a, Int)] -> [(Text, Double)]) -> [(a, Int)] -> [(Text, Double)]
forall a b. (a -> b) -> a -> b
$ Vector a -> [(a, Int)]
forall a. (Ord a, Unbox a) => Vector a -> [(a, Int)]
countValuesUnboxed Vector a
vec
| Just a :~: Word8
Refl <- TypeRep a -> TypeRep Word8 -> Maybe (a :~: Word8)
forall a b. TypeRep a -> TypeRep b -> Maybe (a :~: b)
forall {k} (f :: k -> *) (a :: k) (b :: k).
TestEquality f =>
f a -> f b -> Maybe (a :~: b)
testEquality TypeRep a
tr (forall a. Typeable a => TypeRep a
forall {k} (a :: k). Typeable a => TypeRep a
typeRep @Word8) =
[(a, Int)] -> [(Text, Double)]
forall a. Show a => [(a, Int)] -> [(Text, Double)]
toPairs ([(a, Int)] -> [(Text, Double)]) -> [(a, Int)] -> [(Text, Double)]
forall a b. (a -> b) -> a -> b
$ Vector a -> [(a, Int)]
forall a. (Ord a, Unbox a) => Vector a -> [(a, Int)]
countValuesUnboxed Vector a
vec
| Bool
otherwise = [a] -> [(Text, Double)]
forall a. Show a => [a] -> [(Text, Double)]
countByShow ([a] -> [(Text, Double)]) -> [a] -> [(Text, Double)]
forall a b. (a -> b) -> a -> b
$ Vector a -> [a]
forall a. Unbox a => Vector a -> [a]
VU.toList Vector a
vec
toPairs :: (Show a) => [(a, Int)] -> [(T.Text, Double)]
toPairs :: forall a. Show a => [(a, Int)] -> [(Text, Double)]
toPairs = ((a, Int) -> (Text, Double)) -> [(a, Int)] -> [(Text, Double)]
forall a b. (a -> b) -> [a] -> [b]
map (\(a
k, Int
v) -> (String -> Text
T.pack (a -> String
forall a. Show a => a -> String
show a
k), Int -> Double
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
v))
toPairsText :: [(T.Text, Int)] -> [(T.Text, Double)]
toPairsText :: [(Text, Int)] -> [(Text, Double)]
toPairsText = ((Text, Int) -> (Text, Double))
-> [(Text, Int)] -> [(Text, Double)]
forall a b. (a -> b) -> [a] -> [b]
map ((Int -> Double) -> (Text, Int) -> (Text, Double)
forall b c a. (b -> c) -> (a, b) -> (a, c)
forall (p :: * -> * -> *) b c a.
Bifunctor p =>
(b -> c) -> p a b -> p a c
Data.Bifunctor.second Int -> Double
forall a b. (Integral a, Num b) => a -> b
fromIntegral)
countValues :: (Ord a) => V.Vector a -> [(a, Int)]
countValues :: forall a. Ord a => Vector a -> [(a, Int)]
countValues Vector a
vec = Map a Int -> [(a, Int)]
forall k a. Map k a -> [(k, a)]
M.toList (Map a Int -> [(a, Int)]) -> Map a Int -> [(a, Int)]
forall a b. (a -> b) -> a -> b
$ (a -> Map a Int -> Map a Int) -> Map a Int -> Vector a -> Map a Int
forall a b. (a -> b -> b) -> b -> Vector a -> b
V.foldr' (\a
x Map a Int
acc -> (Int -> Int -> Int) -> a -> Int -> Map a Int -> Map a Int
forall k a. Ord k => (a -> a -> a) -> k -> a -> Map k a -> Map k a
M.insertWith Int -> Int -> Int
forall a. Num a => a -> a -> a
(+) a
x Int
1 Map a Int
acc) Map a Int
forall k a. Map k a
M.empty Vector a
vec
countValuesUnboxed :: (Ord a, VU.Unbox a) => VU.Vector a -> [(a, Int)]
countValuesUnboxed :: forall a. (Ord a, Unbox a) => Vector a -> [(a, Int)]
countValuesUnboxed Vector a
vec = Map a Int -> [(a, Int)]
forall k a. Map k a -> [(k, a)]
M.toList (Map a Int -> [(a, Int)]) -> Map a Int -> [(a, Int)]
forall a b. (a -> b) -> a -> b
$ (a -> Map a Int -> Map a Int) -> Map a Int -> Vector a -> Map a Int
forall a b. Unbox a => (a -> b -> b) -> b -> Vector a -> b
VU.foldr' (\a
x Map a Int
acc -> (Int -> Int -> Int) -> a -> Int -> Map a Int -> Map a Int
forall k a. Ord k => (a -> a -> a) -> k -> a -> Map k a -> Map k a
M.insertWith Int -> Int -> Int
forall a. Num a => a -> a -> a
(+) a
x Int
1 Map a Int
acc) Map a Int
forall k a. Map k a
M.empty Vector a
vec
countByShow :: (Show a) => [a] -> [(T.Text, Double)]
countByShow :: forall a. Show a => [a] -> [(Text, Double)]
countByShow [a]
xs =
((String, Int) -> (Text, Double))
-> [(String, Int)] -> [(Text, Double)]
forall a b. (a -> b) -> [a] -> [b]
map ((String -> Text)
-> (Int -> Double) -> (String, Int) -> (Text, Double)
forall a b c d. (a -> b) -> (c -> d) -> (a, c) -> (b, d)
forall (p :: * -> * -> *) a b c d.
Bifunctor p =>
(a -> b) -> (c -> d) -> p a c -> p b d
Data.Bifunctor.bimap String -> Text
T.pack Int -> Double
forall a b. (Integral a, Num b) => a -> b
fromIntegral) ([(String, Int)] -> [(Text, Double)])
-> [(String, Int)] -> [(Text, Double)]
forall a b. (a -> b) -> a -> b
$
Map String Int -> [(String, Int)]
forall k a. Map k a -> [(k, a)]
M.toList (Map String Int -> [(String, Int)])
-> Map String Int -> [(String, Int)]
forall a b. (a -> b) -> a -> b
$
(Map String Int -> a -> Map String Int)
-> Map String Int -> [a] -> Map String Int
forall b a. (b -> a -> b) -> b -> [a] -> b
forall (t :: * -> *) b a.
Foldable t =>
(b -> a -> b) -> b -> t a -> b
L.foldl' (\Map String Int
acc a
x -> (Int -> Int -> Int)
-> String -> Int -> Map String Int -> Map String Int
forall k a. Ord k => (a -> a -> a) -> k -> a -> Map k a -> Map k a
M.insertWith Int -> Int -> Int
forall a. Num a => a -> a -> a
(+) (a -> String
forall a. Show a => a -> String
show a
x) (Int
1 :: Int) Map String Int
acc) Map String Int
forall k a. Map k a
M.empty [a]
xs
groupWithOther :: Int -> [(T.Text, Double)] -> [(T.Text, Double)]
groupWithOther :: Int -> [(Text, Double)] -> [(Text, Double)]
groupWithOther Int
n [(Text, Double)]
items =
let sorted :: [(Text, Double)]
sorted = ((Text, Double) -> Double) -> [(Text, Double)] -> [(Text, Double)]
forall b a. Ord b => (a -> b) -> [a] -> [a]
L.sortOn (Double -> Double
forall a. Num a => a -> a
negate (Double -> Double)
-> ((Text, Double) -> Double) -> (Text, Double) -> Double
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Text, Double) -> Double
forall a b. (a, b) -> b
snd) [(Text, Double)]
items
([(Text, Double)]
topN, [(Text, Double)]
rest) = Int -> [(Text, Double)] -> ([(Text, Double)], [(Text, Double)])
forall a. Int -> [a] -> ([a], [a])
splitAt Int
n [(Text, Double)]
sorted
otherSum :: Double
otherSum = [Double] -> Double
forall a. Num a => [a] -> a
forall (t :: * -> *) a. (Foldable t, Num a) => t a -> a
sum (((Text, Double) -> Double) -> [(Text, Double)] -> [Double]
forall a b. (a -> b) -> [a] -> [b]
map (Text, Double) -> Double
forall a b. (a, b) -> b
snd [(Text, Double)]
rest)
in if [(Text, Double)] -> Bool
forall a. [a] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null [(Text, Double)]
rest Bool -> Bool -> Bool
|| Double
otherSum Double -> Double -> Bool
forall a. Eq a => a -> a -> Bool
== Double
0
then [(Text, Double)]
topN
else [(Text, Double)]
topN [(Text, Double)] -> [(Text, Double)] -> [(Text, Double)]
forall a. [a] -> [a] -> [a]
++ [(Text
"Other (" Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> String -> Text
T.pack (Int -> String
forall a. Show a => a -> String
show ([(Text, Double)] -> Int
forall a. [a] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length [(Text, Double)]
rest)) Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
" items)", Double
otherSum)]
groupWithOtherForPie :: Int -> [(T.Text, Double)] -> [(T.Text, Double)]
groupWithOtherForPie :: Int -> [(Text, Double)] -> [(Text, Double)]
groupWithOtherForPie Int
n [(Text, Double)]
items =
let total :: Double
total = [Double] -> Double
forall a. Num a => [a] -> a
forall (t :: * -> *) a. (Foldable t, Num a) => t a -> a
sum (((Text, Double) -> Double) -> [(Text, Double)] -> [Double]
forall a b. (a -> b) -> [a] -> [b]
map (Text, Double) -> Double
forall a b. (a, b) -> b
snd [(Text, Double)]
items)
sorted :: [(Text, Double)]
sorted = ((Text, Double) -> Double) -> [(Text, Double)] -> [(Text, Double)]
forall b a. Ord b => (a -> b) -> [a] -> [a]
L.sortOn (Double -> Double
forall a. Num a => a -> a
negate (Double -> Double)
-> ((Text, Double) -> Double) -> (Text, Double) -> Double
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Text, Double) -> Double
forall a b. (a, b) -> b
snd) [(Text, Double)]
items
([(Text, Double)]
topN, [(Text, Double)]
rest) = Int -> [(Text, Double)] -> ([(Text, Double)], [(Text, Double)])
forall a. Int -> [a] -> ([a], [a])
splitAt Int
n [(Text, Double)]
sorted
otherSum :: Double
otherSum = [Double] -> Double
forall a. Num a => [a] -> a
forall (t :: * -> *) a. (Foldable t, Num a) => t a -> a
sum (((Text, Double) -> Double) -> [(Text, Double)] -> [Double]
forall a b. (a -> b) -> [a] -> [b]
map (Text, Double) -> Double
forall a b. (a, b) -> b
snd [(Text, Double)]
rest)
otherPct :: Int
otherPct = if Double
total Double -> Double -> Bool
forall a. Eq a => a -> a -> Bool
== Double
0 then Int
0 else Double -> Int
forall b. Integral b => Double -> b
forall a b. (RealFrac a, Integral b) => a -> b
round (Double
100 Double -> Double -> Double
forall a. Num a => a -> a -> a
* Double
otherSum Double -> Double -> Double
forall a. Fractional a => a -> a -> a
/ Double
total) :: Int
in if [(Text, Double)] -> Bool
forall a. [a] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null [(Text, Double)]
rest Bool -> Bool -> Bool
|| Double
otherSum Double -> Double -> Bool
forall a. Eq a => a -> a -> Bool
== Double
0
then [(Text, Double)]
topN
else
[(Text, Double)]
topN
[(Text, Double)] -> [(Text, Double)] -> [(Text, Double)]
forall a. [a] -> [a] -> [a]
++ [
( Text
"Other ("
Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> String -> Text
T.pack (Int -> String
forall a. Show a => a -> String
show ([(Text, Double)] -> Int
forall a. [a] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length [(Text, Double)]
rest))
Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
" items, "
Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> String -> Text
T.pack (Int -> String
forall a. Show a => a -> String
show Int
otherPct)
Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
"%)"
, Double
otherSum
)
]