gtable/fast.py
@jit(nopython=True, nogil=True, cache=True)
def apply_fast_and(value_left, value_right, index_left, index_right):
    index = index_left * index_right
    if len(value_left) > len(value_right):
        result = np.empty(len(value_left), dtype=np.bool_)
    else:
        result = np.empty(len(value_right), dtype=np.bool_)

    cursor_left = 0
    cursor_right = 0
    cursor_result = 0

    for il, ir in zip(index_left, index_right):
        if il & ir:
            if value_left[cursor_left] and value_right[cursor_right]:
                result[cursor_result] = 1
            else:
                result[cursor_result] = 0
            cursor_result += 1
            cursor_left += 1
            cursor_right += 1

        elif il:
            cursor_left += 1

        elif ir:
            cursor_right += 1

    return result[:cursor_result], index
gtable/fast.py
@jit(nopython=True, nogil=True, cache=True)
def apply_fast_xor(value_left, value_right, index_left, index_right):
    index = index_left * index_right
    if len(value_left) > len(value_right):
        result = np.empty(len(value_left), dtype=np.bool_)
    else:
        result = np.empty(len(value_right), dtype=np.bool_)

    cursor_left = 0
    cursor_right = 0
    cursor_result = 0

    for il, ir in zip(index_left, index_right):
        if il & ir:
            if value_left[cursor_left]:
                if value_right[cursor_right]:
                    result[cursor_result] = 0
                else:
                    result[cursor_result] = 1
            else:
                if value_right[cursor_right]:
                    result[cursor_result] = 1
                else:
                    result[cursor_result] = 0
            cursor_result += 1
            cursor_left += 1
            cursor_right += 1

        elif il:
            cursor_left += 1

        elif ir:
            cursor_right += 1

    return result[:cursor_result], index
gtable/fast.py
@jit(nopython=True, nogil=True, cache=True)
def apply_fast_or(value_left, value_right, index_left, index_right):
    index = index_left * index_right
    if len(value_left) > len(value_right):
        result = np.empty(len(value_left), dtype=np.bool_)
    else:
        result = np.empty(len(value_right), dtype=np.bool_)

    cursor_left = 0
    cursor_right = 0
    cursor_result = 0

    for il, ir in zip(index_left, index_right):
        if il & ir:
            if value_left[cursor_left] or value_right[cursor_right]:
                result[cursor_result] = 1
            else:
                result[cursor_result] = 0
            cursor_result += 1
            cursor_left += 1
            cursor_right += 1

        elif il:
            cursor_left += 1

        elif ir:
            cursor_right += 1

    return result[:cursor_result], index
gtable/lib.py
def fillna_column(values, index, reverse=False, fillvalue=None):
    """
    Fills the non available value sequentially with the previous
    available position.
    """
    # Create the new values array
    new_index = np.ones(index.shape, dtype=np.uint8)

    # Compute the indices where values has to be fetched
    if not reverse:
        indices = np.cumsum(index.astype(np.int8)) - np.array(1)
        if fillvalue is not None:
            new_values = np.empty(indices.shape, values.dtype)
            new_values[np.where(indices >= 0)] = values[
                indices[np.where(indices >= 0)]]
            new_values[np.where(indices < 0)] = fillvalue

        else:
            new_values = values[indices[np.where(indices >= 0)]]

    else:
        indices = np.cumsum(index.astype(np.int8)[::-1]) - np.array(1)
        if fillvalue is not None:
            new_values = np.empty(indices.shape, values.dtype)
            new_values[np.where(indices >= 0)] = values[::-1][
                indices[np.where(indices >= 0)]]
            new_values[np.where(indices < 0)] = fillvalue

        else:
            new_values = values[::-1][indices[np.where(indices >= 0)]]

        new_values = new_values[::-1]

    if fillvalue is None:
        new_index[np.where(indices < 0)] = 0

    if reverse:
        new_index = new_index[::-1]

    return new_values, new_index
gtable/fast.py
@generated_jit(nopython=True, nogil=True, cache=True)
def apply_fast_sub(value_left, value_right, index_left, index_right):
    if value_left.dtype == types.int64 and value_right.dtype == types.int64:
        result_dtype = np.int64
    else:
        result_dtype = np.float64

    def f(value_left, value_right, index_left, index_right):
        index = index_left * index_right
        if len(value_left) > len(value_right):
            result = np.empty(len(value_left), dtype=result_dtype)
        else:
            result = np.empty(len(value_right), dtype=result_dtype)

        cursor_result = 0
        cursor_left = 0
        cursor_right = 0
        for il, ir in zip(index_left, index_right):
            if il & ir:
                result[cursor_result] = value_left[cursor_left] -\
                                        value_right[cursor_right]
                cursor_result += 1
                cursor_left += 1
                cursor_right += 1

            elif il:
                cursor_left += 1

            elif ir:
                cursor_right += 1

        return result[:cursor_result], index

    return f
gtable/fast.py
@jit(nopython=True, nogil=True, cache=True)
def apply_fast_gt(value_left, value_right, index_left, index_right):
    index = index_left * index_right
    if len(value_left) > len(value_right):
        result = np.empty(len(value_left), dtype=np.bool_)
    else:
        result = np.empty(len(value_right), dtype=np.bool_)

    cursor_result = 0
    cursor_left = 0
    cursor_right = 0
    for il, ir in zip(index_left, index_right):
        if il & ir:
            result[cursor_result] = value_left[cursor_left] >\
                                    value_right[cursor_right]
            cursor_result += 1
            cursor_left += 1
            cursor_right += 1

        elif il:
            cursor_left += 1

        elif ir:
            cursor_right += 1

    return result[:cursor_result], index
gtable/fast.py
@generated_jit(nopython=True, nogil=True, cache=True)
def apply_fast_mul(value_left, value_right, index_left, index_right):
    if value_left.dtype == types.int64 and value_right.dtype == types.int64:
        result_dtype = np.int64
    else:
        result_dtype = np.float64

    def f(value_left, value_right, index_left, index_right):
        index = index_left * index_right
        if len(value_left) > len(value_right):
            result = np.empty(len(value_left), dtype=result_dtype)
        else:
            result = np.empty(len(value_right), dtype=result_dtype)

        cursor_result = 0
        cursor_left = 0
        cursor_right = 0
        for il, ir in zip(index_left, index_right):
            if il & ir:
                result[cursor_result] = value_left[cursor_left] *\
                                        value_right[cursor_right]
                cursor_result += 1
                cursor_left += 1
                cursor_right += 1

            elif il:
                cursor_left += 1

            elif ir:
                cursor_right += 1

        return result[:cursor_result], index

    return f
gtable/fast.py
@jit(nopython=True, nogil=True, cache=True)
def apply_fast_ge(value_left, value_right, index_left, index_right):
    index = index_left * index_right
    if len(value_left) > len(value_right):
        result = np.empty(len(value_left), dtype=np.bool_)
    else:
        result = np.empty(len(value_left), dtype=np.bool_)

    cursor_result = 0
    cursor_left = 0
    cursor_right = 0
    for il, ir in zip(index_left, index_right):
        if il & ir:
            result[cursor_result] = value_left[cursor_left] >=\
                                    value_right[cursor_right]
            cursor_result += 1
            cursor_left += 1
            cursor_right += 1

        elif il:
            cursor_left += 1

        elif ir:
            cursor_right += 1

    return result[:cursor_result], index
gtable/fast.py
@jit(nopython=True, nogil=True, cache=True)
def apply_fast_eq(value_left, value_right, index_left, index_right):
    index = index_left * index_right
    if len(value_left) > len(value_right):
        result = np.empty(len(value_left), dtype=np.bool_)
    else:
        result = np.empty(len(value_right), dtype=np.bool_)

    cursor_result = 0
    cursor_left = 0
    cursor_right = 0
    for il, ir in zip(index_left, index_right):
        if il & ir:
            if value_left[cursor_left] == value_right[cursor_right]:
                result[cursor_result] = 1
            else:
                result[cursor_result] = 0
            cursor_result += 1
            cursor_left += 1
            cursor_right += 1

        elif il:
            cursor_left += 1

        elif ir:
            cursor_right += 1

    return result[:cursor_result], index
gtable/fast.py
@generated_jit(nopython=True, nogil=True, cache=True)
def apply_fast_mod(value_left, value_right, index_left, index_right):
    if value_left.dtype == types.int64 and value_right.dtype == types.int64:
        result_dtype = np.int64
    else:
        result_dtype = np.float64

    def f(value_left, value_right, index_left, index_right):
        index = index_left * index_right
        if len(value_left) > len(value_right):
            result = np.empty(len(value_left), dtype=result_dtype)
        else:
            result = np.empty(len(value_right), dtype=result_dtype)

        cursor_result = 0
        cursor_left = 0
        cursor_right = 0
        for il, ir in zip(index_left, index_right):
            if il & ir:
                result[cursor_result] = value_left[cursor_left] %\
                                        value_right[cursor_right]
                cursor_result += 1
                cursor_left += 1
                cursor_right += 1

            elif il:
                cursor_left += 1

            elif ir:
                cursor_right += 1

        return result[:cursor_result], index

    return f
gtable/fast.py
def reindex_column(data, index, global_index):
    new_data_index, new_index = reindex(index, global_index)
    return data[new_data_index], new_index
gtable/fast.py
@jit(nopython=True, nogil=True, cache=True)
def apply_fast_floordiv(value_left, value_right, index_left, index_right):
    index = index_left * index_right
    if len(value_left) > len(value_right):
        result = np.empty(len(value_left), dtype=np.int64)
    else:
        result = np.empty(len(value_right), dtype=np.int64)

    cursor_result = 0
    cursor_left = 0
    cursor_right = 0
    for il, ir in zip(index_left, index_right):
        if il & ir:
            result[cursor_result] = value_left[cursor_left] //\
                                    value_right[cursor_right]
            cursor_result += 1
            cursor_left += 1
            cursor_right += 1

        elif il:
            cursor_left += 1

        elif ir:
            cursor_right += 1

    return result[:cursor_result], index
gtable/fast.py
@generated_jit(nopython=True, nogil=True, cache=True)
def apply_fast_add(value_left, value_right, index_left, index_right):
    if value_left.dtype == types.int64 and value_right.dtype == types.int64:
        result_dtype = np.int64
    else:
        result_dtype = np.float64

    def f(value_left, value_right, index_left, index_right):
        index = index_left * index_right
        if len(value_left) > len(value_right):
            result = np.empty(len(value_left), dtype=result_dtype)
        else:
            result = np.empty(len(value_right), dtype=result_dtype)
        cursor_result = 0
        cursor_left = 0
        cursor_right = 0
        for il, ir in zip(index_left, index_right):
            if il & ir:
                result[cursor_result] = value_left[cursor_left] +\
                                        value_right[cursor_right]
                cursor_result += 1
                cursor_left += 1
                cursor_right += 1

            elif il:
                cursor_left += 1

            elif ir:
                cursor_right += 1

        return result[:cursor_result], index

    return f
gtable/fast.py
@jit(nopython=True, nogil=True, cache=True)
def apply_fast_ne(value_left, value_right, index_left, index_right):
    index = index_left * index_right
    if len(value_left) > len(value_right):
        result = np.empty(len(value_left), dtype=np.bool_)
    else:
        result = np.empty(len(value_right), dtype=np.bool_)

    cursor_result = 0
    cursor_left = 0
    cursor_right = 0
    for il, ir in zip(index_left, index_right):
        if il & ir:
            if value_left[cursor_left] != value_right[cursor_right]:
                result[cursor_result] = 1
            else:
                result[cursor_result] = 0
            cursor_result += 1
            cursor_left += 1
            cursor_right += 1

        elif il:
            cursor_left += 1

        elif ir:
            cursor_right += 1

    return result[:cursor_result], index
gtable/fast.py
@generated_jit(nopython=True, nogil=True, cache=True)
def apply_fast_pow(value_left, value_right, index_left, index_right):
    if value_left.dtype == types.int64 and value_right.dtype == types.int64:
        result_dtype = np.int64
    else:
        result_dtype = np.float64

    def f(value_left, value_right, index_left, index_right):
        index = index_left * index_right
        if len(value_left) > len(value_right):
            result = np.empty(len(value_left), dtype=result_dtype)
        else:
            result = np.empty(len(value_right), dtype=result_dtype)

        cursor_result = 0
        cursor_left = 0
        cursor_right = 0
        for il, ir in zip(index_left, index_right):
            if il & ir:
                result[cursor_result] = value_left[cursor_left] **\
                                        value_right[cursor_right]
                cursor_result += 1
                cursor_left += 1
                cursor_right += 1

            elif il:
                cursor_left += 1

            elif ir:
                cursor_right += 1

        return result[:cursor_result], index

    return f
gtable/fast.py
@jit(nopython=True, nogil=True, cache=True)
def apply_fast_lt(value_left, value_right, index_left, index_right):
    index = index_left * index_right
    if len(value_left) > len(value_right):
        result = np.empty(len(value_left), dtype=np.bool_)
    else:
        result = np.empty(len(value_right), dtype=np.bool_)

    cursor_result = 0
    cursor_left = 0
    cursor_right = 0
    for il, ir in zip(index_left, index_right):
        if il & ir:
            result[cursor_result] = value_left[cursor_left] <\
                                    value_right[cursor_right]
            cursor_result += 1
            cursor_left += 1
            cursor_right += 1

        elif il:
            cursor_left += 1

        elif ir:
            cursor_right += 1

    return result[:cursor_result], index
gtable/fast.py
@generated_jit(nopython=True, nogil=True, cache=True)
def apply_fast_truediv(value_left, value_right, index_left, index_right):
    if value_left.dtype == types.int64 and value_right.dtype == types.int64:
        result_dtype = np.int64
    else:
        result_dtype = np.float64

    def f(value_left, value_right, index_left, index_right):
        index = index_left * index_right
        if len(value_left) > len(value_right):
            result = np.empty(len(value_left), dtype=result_dtype)
        else:
            result = np.empty(len(value_right), dtype=result_dtype)

        cursor_result = 0
        cursor_left = 0
        cursor_right = 0
        for il, ir in zip(index_left, index_right):
            if il & ir:
                result[cursor_result] = value_left[cursor_left] /\
                                        value_right[cursor_right]
                cursor_result += 1
                cursor_left += 1
                cursor_right += 1

            elif il:
                cursor_left += 1

            elif ir:
                cursor_right += 1

        return result[:cursor_result], index

    return f
gtable/fast.py
@jit(nopython=True, nogil=True, cache=True)
def apply_mask_column(data, index, mask):
    """
    Sieve picks a mask over data and returns the filtered data array and index
    """
    new_data = data[mask]
    new_index = np.empty_like(index)

    data_cursor = 0
    for i, idx in enumerate(index):
        if idx:
            if mask[data_cursor]:
                new_index[i] = 1
            else:
                new_index[i] = 0
            data_cursor += 1
        else:
            new_index[i] = 0

    return new_data, new_index
gtable/fast.py
@jit(nopython=True, nogil=True, cache=True)
def apply_fast_le(value_left, value_right, index_left, index_right):
    index = index_left * index_right
    if len(value_left) > len(value_right):
        result = np.empty(len(value_left), dtype=np.bool_)
    else:
        result = np.empty(len(value_right), dtype=np.bool_)

    cursor_result = 0
    cursor_left = 0
    cursor_right = 0
    for il, ir in zip(index_left, index_right):
        if il & ir:
            result[cursor_result] = value_left[cursor_left] <=\
                                    value_right[cursor_right]
            cursor_result += 1
            cursor_left += 1
            cursor_right += 1

        elif il:
            cursor_left += 1

        elif ir:
            cursor_right += 1

    return result[:cursor_result], index


Question: import numpy as np
import operator
from gtable.lib import fillna_column
from gtable.fast import apply_fast_add, apply_fast_mul, apply_fast_truediv, \
    apply_fast_sub, apply_fast_floordiv, apply_fast_and, apply_fast_or, \
    apply_fast_xor, apply_fast_pow, apply_fast_mod, apply_fast_ge, \
    apply_fast_gt, apply_fast_le, apply_fast_lt, apply_fast_eq, apply_fast_ne, \
    apply_mask_column, reindex_column
        """
        if isinstance(item, np.ndarray):
            return Column(np.in1d(self.values, item), self.index)
        elif type(item) == Column:
            return Column(np.in1d(self.values, item.values), self.index)
        else:
            raise ValueError('Argument must be an array or a column.')


def apply_add(left: Column, right):
    if type(right) == Column:
        result, index = apply_fast_add(left.values, right.values,
                                       left.index, right.index)
        return Column(result, index)
    else:
        return Column(operator.add(left.values, right), left.index)


def apply_sub(left: Column, right):
    if type(right) == Column:
        result, index = apply_fast_sub(left.values, right.values,
                                       left.index, right.index)
        return Column(result, index)

    else:
        return Column(operator.sub(left.values, right), left.index)

    
def apply_mul(left: Column, right):
    if type(right) == Column:
        result, index = apply_fast_mul(left.values, right.values,
                                       left.index, right.index)
        return Column(result, index)

    else:
        return Column(operator.mul(left.values, right), left.index)


def apply_truediv(left: Column, right):
    if type(right) == Column:
        result, index = apply_fast_truediv(left.values, right.values,
                                           left.index, right.index)
        return Column(result, index)
        
    else:
        return Column(operator.truediv(left.values, right), left.index)
    
    
def apply_floordiv(left: Column, right):
    if type(right) == Column:
        result, index = apply_fast_floordiv(left.values, right.values,
                                            left.index, right.index)
        return Column(result, index)

    else:
        return Column(operator.floordiv(left.values, right), left.index)


def apply_pow(left: Column, right):
    if type(right) == Column:
        result, index = apply_fast_pow(left.values, right.values,
                                       left.index, right.index)
        return Column(result, index)

    else:
        return Column(operator.pow(left.values, right), left.index)


def apply_mod(left: Column, right):
    if type(right) == Column:
        result, index = apply_fast_mod(left.values, right.values,
                                       left.index, right.index)
        return Column(result, index)

    else:
        return Column(operator.mod(left.values, right), left.index)
    

def apply_gt(left: Column, right):
    if type(right) == Column:
        result, index = apply_fast_gt(left.values, right.values,
                                      left.index, right.index)
        return Column(result, index)

    else:
        return Column(operator.gt(left.values, right), left.index)


def apply_ge(left: Column, right):
    if type(right) == Column:
        result, index = apply_fast_ge(left.values, right.values,
                                      left.index, right.index)
        return Column(result, index)

    else:
        return Column(operator.ge(left.values, right), left.index)

    
def apply_lt(left: Column, right):
    if type(right) == Column:
        result, index = apply_fast_lt(left.values, right.values,
                                      left.index, right.index)
        return Column(result, index)

    else:
        return Column(operator.lt(left.values, right), left.index)

    
def apply_le(left: Column, right):
    if type(right) == Column:
        result, index = apply_fast_le(left.values, right.values,
                                      left.index, right.index)
        return Column(result, index)

    else:
        return Column(operator.le(left.values, right), left.index)

    
def apply_and(left: Column, right):
    if type(right) == Column:

Answer:         result, index = apply_fast_and(left.values, right.values,