def map(self, f):
        """
        Map a function from str -> str element-wise over ``self``.

        ``f`` will be applied exactly once to each non-missing unique value in
        ``self``. Missing values will always map to ``self.missing_value``.
        """
        # f() should only return None if None is our missing value.
        if self.missing_value is None:
            allowed_outtypes = self.SUPPORTED_SCALAR_TYPES
        else:
            allowed_outtypes = self.SUPPORTED_NON_NONE_SCALAR_TYPES

        def f_to_use(x,
                     missing_value=self.missing_value,
                     otypes=allowed_outtypes):

            # Don't call f on the missing value; those locations don't exist
            # semantically. We return _sortable_sentinel rather than None
            # because the np.unique call below sorts the categories array,
            # which raises an error on Python 3 because None and str aren't
            # comparable.
            if x == missing_value:
                return _sortable_sentinel

            ret = f(x)

            if not isinstance(ret, otypes):
                raise TypeError(
                    "LabelArray.map expected function {f} to return a string"
                    " or None, but got {type} instead.\n"
                    "Value was {value}.".format(
                        f=f.__name__,
                        type=type(ret).__name__,
                        value=ret,
                    )
                )

            if ret == missing_value:
                return _sortable_sentinel

            return ret

        new_categories_with_duplicates = (
            np.vectorize(f_to_use, otypes=[object])(self.categories)
        )

        # If f() maps multiple inputs to the same output, then we can end up
        # with the same code duplicated multiple times. Compress the categories
        # by running them through np.unique, and then use the reverse lookup
        # table to compress codes as well.
        new_categories, bloated_inverse_index = np.unique(
            new_categories_with_duplicates,
            return_inverse=True
        )

        if new_categories[0] is _sortable_sentinel:
            # f_to_use return _sortable_sentinel for locations that should be
            # missing values in our output. Since np.unique returns the uniques
            # in sorted order, and since _sortable_sentinel sorts before any
            # string, we only need to check the first array entry.
            new_categories[0] = self.missing_value

        # `reverse_index` will always be a 64 bit integer even if we can hold a
        # smaller array.
        reverse_index = bloated_inverse_index.astype(
            smallest_uint_that_can_hold(len(new_categories))
        )
        new_codes = np.take(reverse_index, self.as_int_array())

        return self.from_codes_and_metadata(
            new_codes,
            new_categories,
            dict(zip(new_categories, range(len(new_categories)))),
            missing_value=self.missing_value,
        )
def map ( self , f ) : if self . missing_value is None : allowed_outtypes = self . SUPPORTED_SCALAR_TYPES else : allowed_outtypes = self . SUPPORTED_NON_NONE_SCALAR_TYPES def f_to_use ( x , missing_value = self . missing_value , otypes = allowed_outtypes ) : if x == missing_value : return _sortable_sentinel ret = f ( x ) if not isinstance ( ret , otypes ) : raise TypeError ( "LabelArray.map expected function {f} to return a string" " or None, but got {type} instead.\n" "Value was {value}." . format ( f = f . __name__ , type = type ( ret ) . __name__ , value = ret , ) ) if ret == missing_value : return _sortable_sentinel return ret new_categories_with_duplicates = ( np . vectorize ( f_to_use , otypes = [ object ] ) ( self . categories ) ) new_categories , bloated_inverse_index = np . unique ( new_categories_with_duplicates , return_inverse = True ) if new_categories [ 0 ] is _sortable_sentinel : new_categories [ 0 ] = self . missing_value reverse_index = bloated_inverse_index . astype ( smallest_uint_that_can_hold ( len ( new_categories ) ) ) new_codes = np . take ( reverse_index , self . as_int_array ( ) ) return self . from_codes_and_metadata ( new_codes , new_categories , dict ( zip ( new_categories , range ( len ( new_categories ) ) ) ) , missing_value = self . missing_value , )
Map a function from str -> str element-wise over ``self``.

        ``f`` will be applied exactly once to each non-missing unique value in
        ``self``. Missing values will always map to ``self.missing_value``.