| 181 | } |
| 182 | |
| 183 | func (s *DiscreteStats) summary(a []string) { |
| 184 | s.data = a |
| 185 | s.count = len(a) |
| 186 | |
| 187 | // Count empty/missing values |
| 188 | s.missing = 0 |
| 189 | s.counter = make(map[string]int) |
| 190 | |
| 191 | for _, row := range a { |
| 192 | if row == "" { |
| 193 | s.missing++ |
| 194 | } |
| 195 | s.counter[row]++ |
| 196 | } |
| 197 | |
| 198 | s.unique = len(s.counter) |
| 199 | |
| 200 | type kv struct { |
| 201 | Key string |
| 202 | Value int |
| 203 | } |
| 204 | |
| 205 | // Sort map by value (frequency) |
| 206 | var ss []kv |
| 207 | for k, v := range s.counter { |
| 208 | ss = append(ss, kv{k, v}) |
| 209 | } |
| 210 | |
| 211 | sort.Slice(ss, func(i, j int) bool { |
| 212 | return ss[i].Value > ss[j].Value |
| 213 | }) |
| 214 | |
| 215 | // Build summary with overview first |
| 216 | s.summaryData = [][]string{ |
| 217 | {"Total values", I2S(s.count)}, |
| 218 | {"Unique values", I2S(s.unique)}, |
| 219 | {"Empty/Missing", I2S(s.missing)}, |
| 220 | {"", ""}, |
| 221 | {"Value", "Frequency"}, |
| 222 | {"─────", "─────────"}, |
| 223 | } |
| 224 | |
| 225 | // Add top values (limit to prevent excessive display) |
| 226 | maxDisplay := 50 |
| 227 | for i, kv := range ss { |
| 228 | if i >= maxDisplay { |
| 229 | remaining := len(ss) - maxDisplay |
| 230 | s.summaryData = append(s.summaryData, []string{"...", "(" + I2S(remaining) + " more)"}) |
| 231 | break |
| 232 | } |
| 233 | |
| 234 | displayKey := kv.Key |
| 235 | if displayKey == "" { |
| 236 | displayKey = "(empty)" |
| 237 | } |
| 238 | // Truncate very long values |
| 239 | if len(displayKey) > 40 { |
| 240 | displayKey = displayKey[:37] + "..." |