@@ -257,7 +257,7 @@ def _disallow_invalid_ops(self, dtype: DtypeObj, is_numeric: bool = False):
257
257
# don't go down a group-by-group path, since in the empty-groups
258
258
# case that would fail to raise
259
259
raise TypeError (f"Cannot perform { how } with non-ordered Categorical" )
260
- if how not in ["rank" , "any" , "all" ]:
260
+ if how not in ["rank" , "any" , "all" , "first" , "last" , "min" , "max" ]:
261
261
# only "rank" is implemented in cython
262
262
raise NotImplementedError (f"{ dtype } dtype not supported" )
263
263
@@ -356,11 +356,17 @@ def _ea_wrap_cython_operation(
356
356
)
357
357
358
358
elif isinstance (values , Categorical ):
359
- assert self .how in ["rank" , "any" , "all" ]
359
+ assert self .how in ["rank" , "any" , "all" , "first" , "last" , "min" , "max" ]
360
360
mask = values .isna ()
361
361
if self .how == "rank" :
362
362
assert values .ordered # checked earlier
363
363
npvalues = values ._ndarray
364
+ elif self .how in ["first" , "last" , "min" , "max" ]:
365
+ if self .how in ["min" , "max" ]:
366
+ assert values .ordered # checked earlier
367
+ npvalues = values ._ndarray
368
+ result_mask = np .zeros (ngroups , dtype = np .uint8 )
369
+ kwargs ["result_mask" ] = result_mask
364
370
else :
365
371
npvalues = values .astype (bool )
366
372
@@ -373,9 +379,9 @@ def _ea_wrap_cython_operation(
373
379
** kwargs ,
374
380
)
375
381
376
- # If we ever have more than just "rank" here, we'll need to do
377
- # `if self.how in self.cast_blocklist` like we do for other dtypes.
378
- return res_values
382
+ if self . how in self . cast_blocklist :
383
+ return res_values
384
+ return values . _from_backing_data ( res_values )
379
385
380
386
npvalues = self ._ea_to_cython_values (values )
381
387
0 commit comments