| 169 | === Generic version based on `itertools.groupby` === |
| 170 | |
| 171 | {{{ |
| 172 | from itertools import groupby |
| 173 | |
| 174 | def countdistinct(iterable, groups=None, key=None): |
| 175 | """Count things. |
| 176 | |
| 177 | >>> items = ['red', 'green', 'blue', 'blue'] |
| 178 | >>> countdistinct(items) |
| 179 | {'blue': 2, 'green': 1, 'red': 1} |
| 180 | |
| 181 | You can ensure that specific groups are always included in the result, even |
| 182 | if they don't occur in the input: |
| 183 | |
| 184 | >>> items = ['red', 'blue', 'blue'] |
| 185 | >>> countdistinct(items, groups=['red', 'green', 'blue']) |
| 186 | {'blue': 2, 'green': 0, 'red': 1} |
| 187 | |
| 188 | The optional `key` argument can be used to provide a function that returns |
| 189 | the comparison key for every item: |
| 190 | |
| 191 | >>> from operator import itemgetter |
| 192 | >>> items = [dict(name='foo', category='buzz'), |
| 193 | ... dict(name='bar', category='buzz')] |
| 194 | >>> print countdistinct(items, key=itemgetter('category')) |
| 195 | {'buzz': 2} |
| 196 | """ |
| 197 | return dict([(g, 0) for g in groups] + |
| 198 | [(g, len(list(l))) for g, l in groupby(iterable, key=key)]) |
| 199 | }}} |
| 200 | |