apply(fn, dtype=None, skip_na=True, seed=None)

        Transform each element of the SArray by a given function. The result
        SArray is of type ``dtype``. ``fn`` should be a function that returns
        exactly one value which can be cast into the type specified by
        ``dtype``. If ``dtype`` is not specified, the first 100 elements of the
        SArray are used to make a guess about the data type.

        Parameters
        ----------
        fn : function
            The function to transform each element. Must return exactly one
            value which can be cast into the type specified by ``dtype``.
            This can also be a toolkit extension function which is compiled
            as a native shared library using SDK.


        dtype : {None, int, float, str, list, array.array, dict, turicreate.Image}, optional
            The data type of the new SArray. If ``None``, the first 100 elements
            of the array are used to guess the target data type.

        skip_na : bool, optional
            If True, will not apply ``fn`` to any undefined values.

        seed : int, optional
            Used as the seed if a random number generator is included in ``fn``.

        Returns
        -------
        out : SArray
            The SArray transformed by ``fn``. Each element of the SArray is of
            type ``dtype``.

        See Also
        --------
        SFrame.apply

        Examples
        --------
        >>> sa = turicreate.SArray([1,2,3])
        >>> sa.apply(lambda x: x*2)
        dtype: int
        Rows: 3
        [2, 4, 6]

        Using native toolkit extension function:

        .. code-block:: c++

            #include <turicreate/sdk/toolkit_function_macros.hpp>
            #include <cmath>

            using namespace turi;
            double logx(const flexible_type& x, double base) {
              return log((double)(x)) / log(base);
            }

            BEGIN_FUNCTION_REGISTRATION
            REGISTER_FUNCTION(logx, "x", "base");
            END_FUNCTION_REGISTRATION

        compiled into example.so

        >>> import example

        >>> sa = turicreate.SArray([1,2,4])
        >>> sa.apply(lambda x: example.logx(x, 2))
        dtype: float
        Rows: 3
        [0.0, 1.0, 2.0]

def apply(self, fn, dtype=None, skip_na=True, seed=None):
        """
        apply(fn, dtype=None, skip_na=True, seed=None)

        Transform each element of the SArray by a given function. The result
        SArray is of type ``dtype``. ``fn`` should be a function that returns
        exactly one value which can be cast into the type specified by
        ``dtype``. If ``dtype`` is not specified, the first 100 elements of the
        SArray are used to make a guess about the data type.

        Parameters
        ----------
        fn : function
            The function to transform each element. Must return exactly one
            value which can be cast into the type specified by ``dtype``.
            This can also be a toolkit extension function which is compiled
            as a native shared library using SDK.


        dtype : {None, int, float, str, list, array.array, dict, turicreate.Image}, optional
            The data type of the new SArray. If ``None``, the first 100 elements
            of the array are used to guess the target data type.

        skip_na : bool, optional
            If True, will not apply ``fn`` to any undefined values.

        seed : int, optional
            Used as the seed if a random number generator is included in ``fn``.

        Returns
        -------
        out : SArray
            The SArray transformed by ``fn``. Each element of the SArray is of
            type ``dtype``.

        See Also
        --------
        SFrame.apply

        Examples
        --------
        >>> sa = turicreate.SArray([1,2,3])
        >>> sa.apply(lambda x: x*2)
        dtype: int
        Rows: 3
        [2, 4, 6]

        Using native toolkit extension function:

        .. code-block:: c++

            #include <turicreate/sdk/toolkit_function_macros.hpp>
            #include <cmath>

            using namespace turi;
            double logx(const flexible_type& x, double base) {
              return log((double)(x)) / log(base);
            }

            BEGIN_FUNCTION_REGISTRATION
            REGISTER_FUNCTION(logx, "x", "base");
            END_FUNCTION_REGISTRATION

        compiled into example.so

        >>> import example

        >>> sa = turicreate.SArray([1,2,4])
        >>> sa.apply(lambda x: example.logx(x, 2))
        dtype: float
        Rows: 3
        [0.0, 1.0, 2.0]
        """
        assert callable(fn), "Input function must be callable."

        dryrun = [fn(i) for i in self.head(100) if i is not None]
        if dtype is None:
            dtype = infer_type_of_list(dryrun)
        if seed is None:
            seed = abs(hash("%0.20f" % time.time())) % (2 ** 31)

        # log metric

        # First phase test if it is a toolkit function
        nativefn = None
        try:
            from .. import extensions
            nativefn = extensions._build_native_function_call(fn)
        except:
            # failure are fine. we just fall out into the next few phases
            pass

        if nativefn is not None:
            # this is a toolkit lambda. We can do something about it
            nativefn.native_fn_name = nativefn.native_fn_name.encode()
            with cython_context():
                return SArray(_proxy=self.__proxy__.transform_native(nativefn, dtype, skip_na, seed))

        with cython_context():
            return SArray(_proxy=self.__proxy__.transform(fn, dtype, skip_na, seed))