From 777b94603f5d72d0037bb9a716b1705dd3193b06 Mon Sep 17 00:00:00 2001 From: John Darrington Date: Mon, 25 Oct 2010 13:24:31 +0200 Subject: [PATCH] CROSSTABS: (Re)implemented the format=DVALUE option. This was documented as implemented but in fact, wasn't. --- src/language/stats/crosstabs.q | 39 ++++++++++++++++++++++++++----- tests/language/stats/crosstabs.at | 36 ++++++++++++++++++++++++++++ 2 files changed, 69 insertions(+), 6 deletions(-) diff --git a/src/language/stats/crosstabs.q b/src/language/stats/crosstabs.q index 4f93d6f5..be096bc4 100644 --- a/src/language/stats/crosstabs.q +++ b/src/language/stats/crosstabs.q @@ -198,6 +198,8 @@ struct crosstabs_proc /* STATISTICS. */ unsigned int statistics; /* Bit k is 1 if statistic k is requested. */ + + bool descending; /* True if descending sort order is requested. */ }; static bool should_tabulate_case (const struct pivot_table *, @@ -229,6 +231,7 @@ cmd_crosstabs (struct lexer *lexer, struct dataset *ds) proc.n_variables = 0; proc.pivots = NULL; proc.n_pivots = 0; + proc.descending = false; proc.weight_format = wv ? *var_get_print_format (wv) : F_8_0; if (!parse_crosstabs (lexer, ds, &cmd, &proc)) @@ -239,6 +242,9 @@ cmd_crosstabs (struct lexer *lexer, struct dataset *ds) proc.mode = proc.n_variables ? INTEGER : GENERAL; + + proc.descending = cmd.val == CRS_DVALUE; + /* CELLS. */ if (!cmd.sbc_cells) proc.cells = 1u << CRS_CL_COUNT; @@ -640,8 +646,11 @@ static int compare_table_entry_vars_3way (const struct table_entry *a, int idx0, int idx1); static int compare_table_entry_3way (const void *ap_, const void *bp_, const void *pt_); +static int compare_table_entry_3way_inv (const void *ap_, const void *bp_, + const void *pt_); + static void enum_var_values (const struct pivot_table *, int var_idx, - union value **valuesp, int *n_values); + union value **valuesp, int *n_values, bool descending); static void output_pivot_table (struct crosstabs_proc *, struct pivot_table *); static void make_pivot_table_subset (struct pivot_table *pt, @@ -669,7 +678,8 @@ postcalc (struct crosstabs_proc *proc) hmap_destroy (&pt->data); sort (pt->entries, pt->n_entries, sizeof *pt->entries, - compare_table_entry_3way, pt); + proc->descending ? compare_table_entry_3way_inv : compare_table_entry_3way, + pt); } make_summary_table (proc); @@ -779,6 +789,13 @@ compare_table_entry_3way (const void *ap_, const void *bp_, const void *pt_) return compare_table_entry_var_3way (a, b, pt, COL_VAR); } +/* Inverted version of compare_table_entry_3way */ +static int +compare_table_entry_3way_inv (const void *ap_, const void *bp_, const void *pt_) +{ + return -compare_table_entry_3way (ap_, bp_, pt_); +} + static int find_first_difference (const struct pivot_table *pt, size_t row) { @@ -905,7 +922,7 @@ output_pivot_table (struct crosstabs_proc *proc, struct pivot_table *pt) struct tab_table *direct = NULL; /* Directional measures table. */ size_t row0, row1; - enum_var_values (pt, COL_VAR, &pt->cols, &pt->n_cols); + enum_var_values (pt, COL_VAR, &pt->cols, &pt->n_cols, proc->descending); if (proc->cells) table = create_crosstab_table (proc, pt); @@ -931,7 +948,7 @@ output_pivot_table (struct crosstabs_proc *proc, struct pivot_table *pt) make_pivot_table_subset (pt, row0, row1, &x); /* Find all the row variable values. */ - enum_var_values (&x, ROW_VAR, &x.rows, &x.n_rows); + enum_var_values (&x, ROW_VAR, &x.rows, &x.n_rows, proc->descending); if (size_overflow_p (xtimes (xtimes (x.n_rows, x.n_cols), sizeof (double)))) @@ -1377,6 +1394,14 @@ compare_value_3way (const void *a_, const void *b_, const void *width_) return value_compare_3way (a, b, *width); } +/* Inverted version of the above */ +static int +compare_value_3way_inv (const void *a_, const void *b_, const void *width_) +{ + return -compare_value_3way (a_, b_, width_); +} + + /* Given an array of ENTRY_CNT table_entry structures starting at ENTRIES, creates a sorted list of the values that the variable with index VAR_IDX takes on. The values are returned as a @@ -1385,7 +1410,7 @@ compare_value_3way (const void *a_, const void *b_, const void *width_) */ static void enum_var_values (const struct pivot_table *pt, int var_idx, - union value **valuesp, int *n_values) + union value **valuesp, int *n_values, bool descending) { const struct variable *var = pt->vars[var_idx]; struct var_range *range = get_var_range (var); @@ -1429,7 +1454,9 @@ enum_var_values (const struct pivot_table *pt, int var_idx, values[i++] = *iter; hmapx_destroy (&set); - sort (values, *n_values, sizeof *values, compare_value_3way, &width); + sort (values, *n_values, sizeof *values, + descending ? compare_value_3way_inv : compare_value_3way, + &width); } } diff --git a/tests/language/stats/crosstabs.at b/tests/language/stats/crosstabs.at index e464d846..b0da517f 100644 --- a/tests/language/stats/crosstabs.at +++ b/tests/language/stats/crosstabs.at @@ -342,3 +342,39 @@ Total,,4.0,1.0,5.0 Total,,3.0,1.0,4.0 ]]) AT_CLEANUP + + + +AT_SETUP([CROSSTABS descending sort order]) +AT_DATA([crosstabs-descending.sps], + [[DATA LIST NOTABLE LIST /x * y *. +BEGIN DATA. +2 2 +2 2 +3 1 +4 1 +3 2 +3 2 +END DATA. + +CROSSTABS + /TABLES= x BY y + /FORMAT = DVALUE. +]]) + +AT_CHECK([pspp -O format=csv crosstabs-descending.sps], [0], + [[Table: Summary. +,Cases,,,,, +,Valid,,Missing,,Total, +,N,Percent,N,Percent,N,Percent +x * y,6,100.0%,0,0.0%,6,100.0% + +Table: x * y [count]. +,y,, +x,2.00,1.00,Total +4.00,.0,1.0,1.0 +3.00,2.0,1.0,3.0 +2.00,2.0,.0,2.0 +Total,4.0,2.0,6.0 +]]) +AT_CLEANUP -- 2.30.2