@@ -39,7 +39,16 @@ pub fn summary_stats(
3939 stats. type_display = display_type;
4040 match stats. type_display {
4141 ColumnDisplayType :: Number => {
42- stats. number_stats = Some ( summary_stats_number ( column, format_options) ?) ;
42+ stats. number_stats = Some ( summary_stats_number ( column, format_options, false ) ?) ;
43+ } ,
44+ ColumnDisplayType :: Integer => {
45+ stats. number_stats = Some ( summary_stats_number ( column, format_options, true ) ?) ;
46+ } ,
47+ ColumnDisplayType :: Floating => {
48+ stats. number_stats = Some ( summary_stats_number ( column, format_options, false ) ?) ;
49+ } ,
50+ ColumnDisplayType :: Decimal => {
51+ stats. number_stats = Some ( summary_stats_number ( column, format_options, false ) ?) ;
4352 } ,
4453 ColumnDisplayType :: String => {
4554 stats. string_stats = Some ( summary_stats_string ( column) ?) ;
@@ -59,6 +68,7 @@ pub fn summary_stats(
5968fn summary_stats_number (
6069 column : SEXP ,
6170 format_options : & FormatOptions ,
71+ is_integer : bool ,
6272) -> anyhow:: Result < SummaryStatsNumber > {
6373 let r_stats = call_summary_fn ( "summary_stats_number" , column) ?;
6474
@@ -74,13 +84,38 @@ fn summary_stats_number(
7484 } )
7585 . collect ( ) ;
7686
77- Ok ( SummaryStatsNumber {
78- min_value : r_stats. get ( "min_value" ) . cloned ( ) ,
79- max_value : r_stats. get ( "max_value" ) . cloned ( ) ,
80- mean : r_stats. get ( "mean" ) . cloned ( ) ,
81- median : r_stats. get ( "median" ) . cloned ( ) ,
82- stdev : r_stats. get ( "stdev" ) . cloned ( ) ,
83- } )
87+ let min_value = r_stats. get ( "min_value" ) . cloned ( ) ;
88+ let max_value = r_stats. get ( "max_value" ) . cloned ( ) ;
89+ let mean = r_stats. get ( "mean" ) . cloned ( ) ;
90+ let median = r_stats. get ( "median" ) . cloned ( ) ;
91+ let stdev = r_stats. get ( "stdev" ) . cloned ( ) ;
92+
93+ // For integer types, reformat min/max/median as whole numbers without decimal points.
94+ // Mean and stdev keep their decimal formatting since they can be fractional even for integers.
95+ if is_integer {
96+ let reformat_as_whole_number = |value : Option < String > | -> Option < String > {
97+ value. and_then ( |v| {
98+ // Remove thousands separator, parse, and format as integer
99+ v. replace ( ',' , "" ) . parse :: < f64 > ( ) . ok ( ) . map ( |num| format ! ( "{:.0}" , num) )
100+ } )
101+ } ;
102+
103+ Ok ( SummaryStatsNumber {
104+ min_value : reformat_as_whole_number ( min_value) ,
105+ max_value : reformat_as_whole_number ( max_value) ,
106+ mean,
107+ median : reformat_as_whole_number ( median) ,
108+ stdev,
109+ } )
110+ } else {
111+ Ok ( SummaryStatsNumber {
112+ min_value,
113+ max_value,
114+ mean,
115+ median,
116+ stdev,
117+ } )
118+ }
84119}
85120
86121fn summary_stats_string ( column : SEXP ) -> anyhow:: Result < SummaryStatsString > {
@@ -201,7 +236,7 @@ mod tests {
201236 crate :: r_task ( || {
202237 let column = harp:: parse_eval_global ( "c(1,2,3,4,5, NA)" ) . unwrap ( ) ;
203238 let stats =
204- summary_stats ( column. sexp , ColumnDisplayType :: Number , & default_options ( ) ) . unwrap ( ) ;
239+ summary_stats ( column. sexp , ColumnDisplayType :: Floating , & default_options ( ) ) . unwrap ( ) ;
205240 let expected = SummaryStatsNumber {
206241 min_value : Some ( "1.00" . to_string ( ) ) ,
207242 max_value : Some ( "5.00" . to_string ( ) ) ,
@@ -213,12 +248,29 @@ mod tests {
213248 } )
214249 }
215250
251+ #[ test]
252+ fn test_integer_summary ( ) {
253+ crate :: r_task ( || {
254+ let column = harp:: parse_eval_global ( "c(1L, 2L, 3L, 4L, 5L, NA)" ) . unwrap ( ) ;
255+ let stats =
256+ summary_stats ( column. sexp , ColumnDisplayType :: Integer , & default_options ( ) ) . unwrap ( ) ;
257+ let expected = SummaryStatsNumber {
258+ min_value : Some ( "1" . to_string ( ) ) ,
259+ max_value : Some ( "5" . to_string ( ) ) ,
260+ mean : Some ( "3.00" . to_string ( ) ) ,
261+ median : Some ( "3" . to_string ( ) ) ,
262+ stdev : Some ( "1.58" . to_string ( ) ) ,
263+ } ;
264+ assert_eq ! ( stats. number_stats, Some ( expected) ) ;
265+ } )
266+ }
267+
216268 #[ test]
217269 fn test_numeric_all_nas ( ) {
218270 crate :: r_task ( || {
219271 let column = harp:: parse_eval_global ( "c(NA_real_, NA_real_, NA_real_)" ) . unwrap ( ) ;
220272 let stats =
221- summary_stats ( column. sexp , ColumnDisplayType :: Number , & default_options ( ) ) . unwrap ( ) ;
273+ summary_stats ( column. sexp , ColumnDisplayType :: Floating , & default_options ( ) ) . unwrap ( ) ;
222274 let expected = SummaryStatsNumber {
223275 min_value : None ,
224276 max_value : None ,
0 commit comments