category sort implicitly
authorBen Pfaff <blp@cs.stanford.edu>
Sun, 2 Jan 2022 23:07:02 +0000 (15:07 -0800)
committerBen Pfaff <blp@cs.stanford.edu>
Thu, 13 Jan 2022 05:52:27 +0000 (21:52 -0800)
src/language/stats/ctables.c

index 8277a702b28a165150f1191c0795aa763b1b761c..64ef2a5e64b91607e28f65cf68f4dc609bfb17ec 100644 (file)
@@ -1914,7 +1914,9 @@ ctables_freq_compare_3way (const void *a_, const void *b_, const void *aux_)
           continue;
 
         const struct ctables_categories *cats = aux->t->categories[var_get_dict_index (var)];
-        if (cats && cats->n_values)
+        if (!cats)
+          return cmp;
+        else if (cats->n_values)
           {
             const struct ctables_cat_value *a_cv = ctables_categories_match (cats, val_a, var);
             const struct ctables_cat_value *b_cv = ctables_categories_match (cats, val_b, var);
@@ -1923,8 +1925,32 @@ ctables_freq_compare_3way (const void *a_, const void *b_, const void *aux_)
                     : a_cv > b_cv ? 1
                     : -1);
           }
+        else
+          {
+            switch (cats->key)
+              {
+              case CTCS_VALUE:
+                /* Nothing to do. */
+                break;
 
-        return cmp;
+              case CTCS_LABEL:
+                {
+                  const char *a_label = var_lookup_value_label (var, val_a);
+                  const char *b_label = var_lookup_value_label (var, val_b);
+                  int label_cmp = (a_label
+                                   ? (b_label ? strcmp (a_label, b_label) : 1)
+                                   : (b_label ? -1 : 0));
+                  if (label_cmp)
+                    cmp = label_cmp;
+                }
+                break;
+
+              case CTCS_FUNCTION:
+                NOT_REACHED ();
+              }
+
+            return cats->sort_ascending ? cmp : -cmp;
+          }
       }
   return 0;
 }
@@ -2060,12 +2086,29 @@ ctables_freqtab_insert (struct ctables_table *t,
           if (i == va->scale_idx)
             continue;
 
-          const struct ctables_categories *cats = t->categories[var_get_dict_index (va->vars[i])];
-          if (!cats || !cats->n_values)
-            continue;
+          const struct variable *var = va->vars[i];
+          const union value *value = case_data (c, var);
 
-          if (!ctables_categories_match (cats, case_data (c, va->vars[i]), va->vars[i]))
+          enum mv_class missing = var_is_value_missing (var, value);
+          if (missing == MV_SYSTEM)
             return;
+
+          const struct ctables_categories *cats = t->categories[var_get_dict_index (var)];
+          if (!cats)
+            {
+              if (missing)
+                return;
+            }
+          else if (cats->n_values)
+            {
+              if (!ctables_categories_match (cats, value, var))
+                return;
+            }
+          else
+            {
+              if (missing && !cats->include_missing)
+                return;
+            }
         }
     }