Module funct.Array

Expand source code
import funct.lazy as L

import itertools
import math
import multiprocessing
import operator
import warnings
from collections.abc import Iterable, Sequence
from concurrent.futures import ThreadPoolExecutor
from functools import reduce


class Array(list, L.ASeq):
    """
    A functional mutable sequence
    inheriting from the built-in list.
    """

    __slots__ = []
    __baseIterables = (list, range, tuple)

    def __init__(self, *args):
        """
        Constructs an Array from arguments.
        Nested lists, tuples and range objects are converted to
        Arrays, while other iterables will stored as Array elements.
        """
        if len(args) == 1 and isinstance(args[0], Iterable):
            args = list(args[0])

        if any(map(lambda e: isinstance(e, Array.__baseIterables), args)):
            super().__init__(self.__convert(a) for a in args)
        else:
            super().__init__(args)

    def add(self, e, inplace=False):
        """
        Element-wise addition with given scalar or sequence.
        """
        return self.__operate(operator.add, e, inplace)

    def sub(self, e, inplace=False):
        """
        Element-wise subtraction with given scalar or sequence.
        """
        return self.__operate(operator.sub, e, inplace)

    def mul(self, e, inplace=False):
        """
        Element-wise multiplication with given scalar or sequence.
        """
        return self.__operate(operator.mul, e, inplace)

    def div(self, e, inplace=False):
        """
        Element-wise division with given scalar or sequence.
        """
        return self.__operate(operator.truediv, e, inplace)

    def pow(self, e, inplace=False):
        """
        Raises elements of this Array to given power,
        or sequence of powers, element-wise.
        """
        return self.__operate(operator.pow, e, inplace)

    def mod(self, e, inplace=False):
        """
        Computes the remainder between elements in this Array
        and given scalar or sequence, element-wise.
        """
        return self.__operate(operator.mod, e, inplace)

    def bitwise_and(self, e, inplace=False):
        """
        Computes the bit-wise AND between elements in this Array
        and given scalar or sequence, element-wise.
        """
        return self.__operate(operator.and_, e, inplace)

    def bitwise_or(self, e, inplace=False):
        """
        Computes the bit-wise OR between elements in this Array
        and given scalar or sequence, element-wise.
        """
        return self.__operate(operator.or_, e, inplace)

    def abs(self, inplace=False):
        """ Element-wise absolute value. """
        a = map(abs, self)
        if inplace:
            return self.__setinplace(a, inplace)
        return Array(a)

    def sum(self, start=0):
        """ Returns the sum of the Array elements. """
        return sum(self, start)

    def product(self, start=1):
        """ Returns the product of the Array elements. """
        return reduce(lambda a, b: a * b, self, start)

    def mean(self):
        """ Returns the average of the Array elements. """
        return sum(self) / self.size

    def average(self, weights=None):
        """ Returns the weighted average of the Array elements. """
        if weights is None:
            return sum(self) / self.size
        else:
            self.__validate_seq(weights)
            return sum(self.mul(weights)) / sum(weights)

    def floor(self, inplace=False):
        """ Floors the Array elements. """
        a = map(math.floor, self)
        if inplace:
            return self.__setinplace(a, inplace)
        return Array(a)

    def ceil(self, inplace=False):
        """ Ceils the Array elements. """
        a = map(math.ceil, self)
        if inplace:
            return self.__setinplace(a, inplace)
        return Array(a)

    def round(self, d=0, inplace=False):
        """ Rounds the Array to the given number of decimals. """
        a = map(lambda e: round(e, d), self)
        if inplace:
            return self.__setinplace(a, inplace)
        return Array(a)

    def gt(self, e, inplace=False):
        """ Returns x > y element-wise """
        return self.__operate(operator.gt, e, inplace)

    def ge(self, e, inplace=False):
        """ Returns x >= y element-wise """
        return self.__operate(operator.ge, e, inplace)

    def lt(self, e, inplace=False):
        """ Returns x < y element-wise """
        return self.__operate(operator.lt, e, inplace)

    def le(self, e, inplace=False):
        """ Returns x <= y element-wise """
        return self.__operate(operator.le, e, inplace)

    def eq(self, e, inplace=False):
        """ Returns x == y element-wise """
        return self.__operate(operator.eq, e, inplace)

    def ne(self, e, inplace=False):
        """ Returns x != y element-wise """
        return self.__operate(operator.ne, e, inplace)

    def accumulate(self, func=operator.add):
        """
        Returns accumulated Array of elements using provided function.
        Defaults to accumulated sum.
        """
        return Array(itertools.accumulate(self, func))

    def clip(self, _min, _max, inplace=False):
        """
        Clip the values in the Array between the interval (`_min`, `_max`).
        """
        a = map(lambda e: max(min(e, _max), _min), self)
        if inplace:
            return self.__setinplace(a, inplace)
        return Array(a)

    def roll(self, n, inplace=False):
        """ Rolls the elements of the Array. """
        n = n % self.size
        a = self[-n:] + self[:-n]
        if inplace:
            return self.__setinplace(a, inplace)
        return a

    def cat(self, b):
        """ Concatenates a sequence to this Array. """
        return self + Array(b)

    def diff(self, n=1):
        """ Returns the n-th discrete difference of the Array. """
        if n == 1:
            return self[1:].sub(self[:-1])
        else:
            return self[1:].sub(self[:-1]).diff(n - 1)

    def difference(self, b):
        """
        Difference between this Array and another iterable.
        Returns the values in this Array that are not in sequence b.
        """
        s = set(b)
        return Array(e for e in self if e not in s)

    def setdifference(self, b):
        """
        Difference between this Array and another iterable.
        Returns the unique values in this Array that are not in sequence b.
        Does not preserve order of elements.
        """
        return Array(set(self).difference(set(b)))

    def intersect(self, b):
        """
        Intersection between this Array and another iterable.
        Returns the values that are both in this Array and sequence b.
        """
        s = set(b)
        return Array(e for e in self if e in s)

    def setintersect(self, b):
        """
        Intersection between this Array and another iterable.
        Returns the unique values that are both in this Array and sequence b.
        Does not preserve order of elements.
        """
        return Array(set(self).intersection(set(b)))

    def union(self, b):
        """
        Union of this Array and another iterable.
        Returns the values that are in either this Array or sequence b.
        """
        return self + b

    def setunion(self, b):
        """
        Union of this Array and another iterable.
        Returns the unique values that are in either this Array or sequence b.
        Does not preserve order of elements.
        """
        return Array(set(self).union(set(b)))

    def unique(self):
        """
        Selects unique values in this Array.
        Does not preserve order of elements.
        """
        return Array(set(self))

    def nunique(self):
        """ Returns the number of unique elements in the Array. """
        return len(set(self))

    def equal(self, b):
        """ Returns true this Array and given sequence have the same elements. """
        if len(self) != len(b):
            return False
        return all(self.eq(b))

    def remove(self, b, inplace=False):
        """ Removes first occurence(s) of the value(s). """
        a = self if inplace else self.copy()
        if isinstance(b, Iterable):
            for i in b:
                super(Array, a).remove(i)
        else:
            super(Array, a).remove(b)
        return a

    def remove_by_index(self, b, inplace=False):
        """ Removes the value at specified index or indices. """
        a = self if inplace else self.copy()
        if isinstance(b, Iterable):
            try:
                c = 0
                for i in b:
                    a.pop(i - c)
                    c += 1
            except TypeError:
                raise TypeError(
                    "{} object cannot be interpreted as an integer".format(
                        type(i).__name__
                    )
                ) from None
        else:
            try:
                a.pop(b)
            except TypeError:
                raise TypeError(
                    "{} object cannot be interpreted as an integer".format(
                        type(b).__name__
                    )
                ) from None
        return a

    def get(self, key, default=None):
        """
        Safe method for getting elements in the Array.
        Returns default if the index does not exist.
        """
        try:
            return self[key]
        except IndexError:
            return default

    def map(self, func, inplace=False):
        """
        Returns an Array by applying provided function to all elements of this Array.
        """
        a = map(func, self)
        if inplace:
            return self.__setinplace(a, inplace)
        return Array(a)

    def starmap(self, func):
        """
        Returns an Array by applying provided function
        to this Array with itertools.starmap
        """
        return Array(itertools.starmap(func, self))

    def parmap(self, func, processes=None, Pool=multiprocessing.Pool):
        """
        Returns an Array by applying a function to
        all elements of this Array in parallel.

        Parameters
        ----------
        func: Callable
        processes: int, optional
        Pool: Pool, optional (multiprocessing.Pool, multiprocessing.pool.ThreadPool)
        """
        with Pool(processes=processes) as pool:
            return Array(pool.map(func, self))

    def parstarmap(self, func, processes=None, Pool=multiprocessing.Pool):
        """
        Parallel starmap

        Parameters
        ----------
        func: Callable
        processes: int, optional
        Pool: Pool, optional (multiprocessing.Pool, multiprocessing.pool.ThreadPool)
        """
        with Pool(processes=processes) as pool:
            return Array(pool.starmap(func, self))

    def asyncmap(self, func, Executor=ThreadPoolExecutor):
        """
        Executes map asynchronously.
        Returns a Future object.

        Parameters
        ----------
        func: Callable
        Executor: Executor, optional (concurrent.futures.ThreadPoolExecutor, concurrent.futures.ProcessPoolExecutor)
        """
        with Executor() as executor:
            return executor.submit(self.map, func)

    def asyncstarmap(self, func, Executor=ThreadPoolExecutor):
        """
        Executes starmap asynchronously.
        Returns a Future object.

        Parameters
        ----------
        func: Callable
        Executor: Executor, optional (concurrent.futures.ThreadPoolExecutor, concurrent.futures.ProcessPoolExecutor)
        """
        with Executor() as executor:
            return executor.submit(self.starmap, func)

    def filter(self, func):
        """ Selects elements of this Array which satisfy the predicate. """
        return Array(filter(func, self))

    def forall(self, func):
        """
        Returns whether the specified predicate
        holds for all elements of this Array.
        """
        return all(map(func, self))

    def forany(self, func):
        """
        Returns whether the specified predicate
        holds for any element of this Array.
        """
        return any(map(func, self))

    def foreach(self, func):
        """ Applies `func` to each element of the Array. """
        for e in self:
            func(e)

    def reduce(self, func, init=None):
        """ Reduces the elements of this Array using the specified operator. """
        if init is not None:
            return reduce(func, self, init)
        return reduce(func, self)

    def contains(self, e):
        """ Tests whether element exists in this Array. """
        return e in self

    def index_where(self, func):
        """ Finds the index of the first element satisfying a predicate. """
        for i, v in enumerate(self):
            if func(v):
                return i
        raise ValueError("No matches")

    def indices_where(self, func):
        """ Finds all the indices of the elements satisfying a predicate. """
        return Array(i for i, v in enumerate(self) if func(v))

    def indices(self, e):
        """ Returns all the indices of provided value in this Array. """
        r = []
        o = -1
        while True:
            try:
                o = self.index(e, o + 1)
            except ValueError:
                return Array(r)
            r.append(o)

    def split(self, c):
        """
        Splits an Array into subarrays using provided argument as the delimiter element.
        """
        try:
            i = self.index(c)
            v = self[:i].unsqueeze if i != 0 else Array()
            for e in self[i + 1 :].split(c):
                if len(e) != 0:
                    v.append(e)
            return v
        except ValueError:
            return self.unsqueeze

    def split_to(self, n):
        """ Splits this Array to n equal length subarrays """
        if self.size % n != 0:
            raise ValueError("Split does not result in an equal division")
        d = self.size // n
        return Array(self[d * i : d * (i + 1)] for i in range(n))

    def split_at(self, n):
        """ Splits this Array into subarrays at specified index or indices. """
        if isinstance(n, int):
            return Array(self[:n], self[n:])
        n = Array(0, *n, self.size)
        return Array(self[n[i] : n[i + 1]] for i in range(n.size - 1))

    def chunks(self, n, drop_last=False):
        """
        Splits this Array into chunks of size n.
        If `drop_last` is True, drops the last subarray if the split
        results in an inequal division.
        """
        self.__validate_bool_arg(drop_last, "drop_last")
        fun = int if drop_last else math.ceil
        return Array(self[i * n : (i + 1) * n] for i in range(fun(self.size / n)))

    def windows(self, size, stride=1, drop_last=True):
        """
        Returns sliding windows of width `size` over the Array.
        If `drop_last` is True, drops the last subarrays that are
        shorter than the window size.
        """
        self.__validate_bool_arg(drop_last, "drop_last")
        end = (self.size - size + 1) if drop_last else self.size
        return Array(self[i : i + size] for i in range(0, end, stride))

    def takewhile(self, func):
        """ Takes the longest prefix of elements that satisfy the given predicate. """
        return Array(itertools.takewhile(func, self))

    def dropwhile(self, func):
        """ Drops the longest prefix of elements that satisfy the given predicate. """
        return Array(itertools.dropwhile(func, self))

    def groupby(self, func):
        """
        Groups this Array into an Array of Array-tuples according
        to given discriminator function.
        """
        return Array(
            (e, Array(g)) for e, g in itertools.groupby(sorted(self, key=func), func)
        )

    def maxby(self, func, **kwargs):
        """ Finds the maximum value measured by a function. """
        return max(self, key=func, **kwargs)

    def minby(self, func, **kwargs):
        """ Finds the minimum value measured by a function. """
        return min(self, key=func, **kwargs)

    def sortby(self, func, reverse=False, inplace=False):
        """
        Sorts this Array according to a function
        defining the sorting criteria.
        """
        if inplace:
            self.__validate_bool_arg(inplace, "inplace")
            super().sort(key=func, reverse=reverse)
            return self
        return Array(sorted(self, key=func, reverse=reverse))

    def argsortby(self, func, reverse=False):
        """
        Returns the indices that would sort this Array according to
        provided sorting criteria.
        """
        return self.enumerate.sortby(lambda e: func(e[1]), reverse=reverse)[:, 0]

    def sort(self, inplace=False, **kwargs):
        """ Sorts this Array. """
        if inplace:
            self.__validate_bool_arg(inplace, "inplace")
            super().sort(**kwargs)
            return self
        return Array(sorted(self, **kwargs))

    def argsort(self, reverse=False):
        """ Returns the indices that would sort this Array """
        return self.enumerate.sortby(lambda e: e[1], reverse=reverse)[:, 0]

    def reverse(self, inplace=False):
        """ Reverses this Array. """
        if inplace:
            self.__validate_bool_arg(inplace, "inplace")
            super().reverse()
            return self
        return Array(reversed(self))

    def copy(self):
        return Array(super().copy())

    def astype(self, t):
        """
        Converts the elements in this Array to given type.
        """
        return Array(map(t, self))

    def join(self, delimiter=" "):
        """
        Creates a string representation of this Array
        with elements separated with `delimiter`
        """
        return delimiter.join(str(v) for v in self)

    def append(self, e):
        """
        Appends an element to the end of this Array.
        """
        super().append(self.__convert(e))
        return self

    def prepend(self, e):
        """
        Prepends an element to the beginning of this Array.
        """
        super().insert(0, self.__convert(e))
        return self

    def extend(self, e):
        """ Extend this Array by appending elements from the iterable. """
        super().extend(Array(e))
        return self

    def extendleft(self, e):
        """ Extends this Array by prepending elements from the iterable. """
        self[0:0] = Array(e)
        return self

    def insert(self, i, e):
        """ Inserts element(s) (in place) before given index/indices. """
        if isinstance(e, Array.__baseIterables) and isinstance(
            i, Array.__baseIterables
        ):
            if len(e) != len(i):
                raise ValueError(
                    "The lengths of the sequences must match, got {} and {}".format(
                        len(i), len(e)
                    )
                )
            for ii, ei in zip(i, e):
                self.insert(ii, ei)
        else:
            super().insert(i, self.__convert(e))
        return self

    def fill(self, e, inplace=False):
        """ Replaces all elements of this Array with given object. """
        if inplace:
            return self.__setinplace(e, inplace)
        return Array([e] * self.size)

    def pad(self, n, value=0):
        """ Pads this Array with value. """
        try:
            return self + [value] * n
        except TypeError:
            raise TypeError(
                "{} object cannot be interpreted as an integer".format(type(n).__name__)
            ) from None

    def padleft(self, n, value=0):
        """ Pads this Array with value. """
        try:
            return [value] * n + self
        except TypeError:
            raise TypeError(
                "{} object cannot be interpreted as an integer".format(type(n).__name__)
            ) from None

    def pad_to(self, n, value=0):
        """
        Pads this Array with value until length of n is reached.
        """
        try:
            return self + [value] * (n - self.size)
        except TypeError:
            raise TypeError(
                "{} object cannot be interpreted as an integer".format(type(n).__name__)
            ) from None

    def padleft_to(self, n, value=0):
        """ Pads this Array with value until length of n is reached. """
        try:
            return [value] * (n - self.size) + self
        except TypeError:
            raise TypeError(
                "{} object cannot be interpreted as an integer".format(type(n).__name__)
            ) from None

    def zip(self, *args):
        return Array(zip(self, *args))

    def unzip(self):
        """
        'Unzips' nested Arrays by unpacking its elements into a zip.

        >>> Array((1, "a"), (2, "b")).unzip()
        Array(Array(1, 2), Array('a', 'b'))
        """
        if not all(map(lambda e: isinstance(e, Iterable), self)):
            raise TypeError("Array elements must support iteration")
        return Array(zip(*self))

    def zip_all(self, *args, default=None):
        """
        Zips the sequences. If the iterables are
        of uneven length, missing values are filled with default value.
        """
        return Array(itertools.zip_longest(self, *args, fillvalue=default))

    def all(self):
        """ Returns true if bool(e) is True for all elements in this Array. """
        return all(self)

    def any(self):
        """ Returns true if bool(e) is True for any element e in this Array. """
        return any(self)

    def max(self, **kwargs):
        return max(self, **kwargs)

    def argmax(self):
        """ Returns the index of the maximum value """
        return max(self.enumerate, key=lambda e: e[1])[0]

    def min(self, **kwargs):
        return min(self, **kwargs)

    def argmin(self):
        """ Returns the index of the minimum value """
        return min(self.enumerate, key=lambda e: e[1])[0]

    @property
    def head(self):
        """ Selects the first element of this Array. """
        return self[0]

    def head_option(self, default=None):
        """
        Selects the first element of this Array if it has one,
        otherwise returns default.
        """
        return self.get(0, default)

    @property
    def last(self):
        """ Selects the last element of this Array. """
        return self[-1]

    def last_option(self, default=None):
        """
        Selects the last element of this Array if it has one,
        otherwise returns default.
        """
        return self.get(-1, default)

    @property
    def init(self):
        """ Selects the rest of this Array without its last element. """
        return self[:-1]

    @property
    def tail(self):
        """ Selects the rest of this Array without its first element. """
        return self[1:]

    @property
    def isempty(self):
        """ Returns whether this Array is empty. """
        return self.size == 0

    @property
    def nonempty(self):
        """ Returns whether this Array is not empty. """
        return self.size != 0

    def isfinite(self):
        """
        Tests element-wise whether the elements are neither infinity nor NaN.
        """
        return Array(map(math.isfinite, self))

    @property
    def length(self):
        """ Number of elements in this Array. """
        return self.__len__()

    @property
    def size(self):
        """ Number of elements in this Array. """
        return self.__len__()

    def int(self):
        """ Converts elements in this Array to integers. """
        try:
            return Array(map(lambda e: ord(e) if isinstance(e, str) else int(e), self))
        except TypeError:
            raise TypeError("Expected an Array of numbers or characters") from None

    def float(self):
        """ Converts elements in this Array to floats. """
        return Array(map(float, self))

    def bool(self):
        """ Converts elements in this Array to booleans. """
        return Array(map(bool, self))

    def char(self):
        """ Converts an Array of integers to chars. """
        return Array(map(chr, self))

    def to_str(self):
        """
        Creates a string representation of the Array.
        See Array.join for more functionality.
        """
        return "".join(str(v) for v in self)

    def to_tuple(self):
        """ Returns a copy of the Array as an tuple. """
        return tuple(self.copy())

    def to_set(self):
        """ Returns set of the Array elements. Order is not preserved. """
        return set(self)

    def to_iter(self):
        """ Returns an iterator for the Array."""
        for e in self:
            yield e

    def to_dict(self):
        """ Creates a dictionary from an Array of Arrays / tuples. """
        return dict(self)

    @property
    def squeeze(self):
        """
        Returns the Array with the same elements, but with
        outermost singleton dimension removed (if exists).
        """
        if isinstance(self.head_option(), Array.__baseIterables) and self.length == 1:
            return self[0]
        else:
            return self

    @property
    def unsqueeze(self):
        """
        Returns the Array with the same elements wrapped in a Array.
        """
        return Array([self])

    @property
    def flatten(self):
        """ Returns the Array collapsed into one dimension. """
        r = Array(
            e
            for s in self
            for e in (s if isinstance(s, Array.__baseIterables) else [s])
        )
        if any(map(lambda e: isinstance(e, Array.__baseIterables), r)):
            return r.flatten
        return r

    @property
    def range(self):
        """ Returns the indices of the Array"""
        return Array(range(self.size))

    @property
    def enumerate(self):
        """ Zips the Array with its indices """
        return Array(enumerate(self))

    @staticmethod
    def zeros(n):
        """ Returns a zero-filled Array of given length. """
        try:
            return Array([0] * n)
        except TypeError:
            raise TypeError(
                "{} object cannot be interpreted as an integer".format(type(n).__name__)
            ) from None

    @staticmethod
    def arange(*args):
        """
        Returns an Array of evenly spaced values within given interval

        Parameters
        ----------
        start: number, optional
        end: number
        step: number, optional
        """
        _len = len(args)
        if _len == 0:
            raise TypeError("Expected at least one argument")
        elif _len > 3:
            raise TypeError("Expected at most 3 arguments")
        elif _len == 1:
            return Array(range(math.ceil(args[0])))
        start, end, step = args if _len == 3 else args + (1,)
        return Array(start + step * i for i in range(math.ceil((end - start) / step)))

    @staticmethod
    def linspace(start, stop, num=50, endpoint=True):
        """
        Returns evenly spaced Array over a specified interval.

        Parameters
        ----------
        start: number
        stop: number
        num: int, optional
        endpoint : bool, optional
        """
        Array.__validate_bool_arg(None, endpoint, "endpoint")
        step = (stop - start) / max(num - bool(endpoint), 1)
        return Array(start + step * i for i in range(num))

    @staticmethod
    def logspace(start, stop, num=50, base=10, endpoint=True):
        """
        Returns Array spaced evenly on a log scale.

        Parameters
        ----------
        start: number
        stop: number
        num: int, optional
        base: float, optional
        endpoint: bool, optional
        """
        Array.__validate_bool_arg(None, endpoint, "endpoint")
        return base ** Array.linspace(start, stop, num, endpoint)

    def __convert(self, e):
        return Array(e) if isinstance(e, Array.__baseIterables) else e

    def __validate_index(self, i):
        if not isinstance(i, (int, slice)):
            if not isinstance(i, Sequence) or not all(
                map(lambda e: isinstance(e, (bool, int, slice)), i)
            ):
                raise TypeError(
                    "Only integers, slices and 1d integer or boolean Arrays are valid indices"
                )

    def __validate_setelem(self, i, e):
        if isinstance(e, Iterable):
            if len(i) != len(e):
                raise ValueError(
                    "Expected Array of size {}, got {}".format(len(i), len(e))
                )
            return iter(e)
        else:
            return itertools.repeat(e)

    def __validate_seq(self, e):
        if len(e) != self.size:
            raise ValueError(
                "The lengths of the sequences must match, got {} and {}".format(
                    self.size, len(e)
                )
            )

    def __validate_bool_arg(self, value, name):
        if not isinstance(value, bool):
            raise ValueError(f"Expected type bool for {name} argument")

    def __setinplace(self, s, arg):
        self.__validate_bool_arg(arg, "inplace")
        self[:] = s
        return self

    def __map(self, f, e):
        if isinstance(e, Iterable):
            return map(f, self, e)
        return map(f, self, itertools.repeat(e))

    def __operate(self, op, e, inplace):
        self.__validate_bool_arg(inplace, "inplace")
        a = self.__map(op, e)
        if inplace:
            self[:] = a
            return self
        return Array(a)

    def __repr__(self):
        return "Array" + "(" + super().__repr__()[1:-1] + ")"

    def __add__(self, b):
        if isinstance(b, Array.__baseIterables):
            return Array(super().__add__(Array(b)))
        else:
            raise TypeError(f"Can not concatenate {type(b).__name__} to Array")

    def __iadd__(self, b):
        if isinstance(b, Array.__baseIterables):
            super().__iadd__(b)
            return self
        else:
            raise TypeError(f"Can not concatenate {type(b).__name__} to Array")

    def __radd__(self, b):
        if isinstance(b, Array.__baseIterables):
            return Array(b) + self
        else:
            raise TypeError(f"Can not concatenate {type(b).__name__} to Array")

    def __pow__(self, b):
        return self.pow(b)

    def __rpow__(self, b):
        if isinstance(b, Array.__baseIterables):
            return Array(b).pow(self)
        return Array([b] * self.size).pow(self)

    def __gt__(self, e):
        return self.__operate(operator.gt, e, False)

    def __ge__(self, e):
        return self.__operate(operator.ge, e, False)

    def __lt__(self, e):
        return self.__operate(operator.lt, e, False)

    def __le__(self, e):
        return self.__operate(operator.le, e, False)

    def __eq__(self, e):
        return self.__operate(operator.eq, e, False)

    def __ne__(self, e):
        return self.__operate(operator.ne, e, False)

    def __and__(self, e):
        return self.__operate(operator.and_, e, False)

    def __or__(self, e):
        return self.__operate(operator.or_, e, False)

    def __neg__(self):
        return Array(map(operator.neg, self))

    def __invert__(self):
        if all(map(lambda e: isinstance(e, bool), self)):
            return Array(map(lambda e: not e, self))
        return Array(map(operator.inv, self))

    def __hash__(self):
        return hash(self.to_tuple())

    def __bool__(self):
        if self.__len__() == 0:
            warnings.warn(
                "The truth value of an empty Array is ambiguous. Use `Array.nonEmpty` to check that Array is not empty",
                UserWarning,
            )
        return all(self)

    def __setitem__(self, key, e):
        self.__validate_index(key)
        if isinstance(key, tuple):
            if len(key) == 1:
                key = key[0]
            else:
                if isinstance(key[0], int):
                    self[key[0]][key[1:]] = e
                    return
                try:
                    idx = range(*key[0].indices(self.size))
                    for ic in idx:
                        self[ic][key[1:]]
                    for ic, ie in zip(idx, self.__validate_setelem(idx, e)):
                        self[ic][key[1:]] = ie
                except TypeError:
                    raise IndexError("Too many indices for the Array") from None
                return
        if isinstance(key, int):
            super().__setitem__(key, self.__convert(e))
            return
        if isinstance(key, Sequence):
            for _i, _e in zip(key, self.__validate_setelem(key, e)):
                super().__setitem__(_i, _e)
            return
        if isinstance(e, Iterable):
            e = self.__convert(e)
        else:
            e = [e] * len(range(*key.indices(self.size)))
        super().__setitem__(key, e)

    def __getitem__(self, key):
        self.__validate_index(key)
        if isinstance(key, tuple):
            if len(key) == 1:
                key = key[0]
            else:
                if isinstance(key[0], int):
                    return self[key[0]][key[1:]]
                try:
                    return Array(e[key[1:]] for e in super().__getitem__(key[0]))
                except TypeError:
                    raise IndexError("Too many indices for the Array") from None
        if isinstance(key, int):
            return super().__getitem__(key)
        if isinstance(key, slice):
            return Array(super().__getitem__(key))
        if all(map(lambda k: isinstance(k, bool), key)):
            if len(key) != self.size:
                raise IndexError(
                    "Expected boolean Array of size {}, got {}".format(
                        self.size, len(key)
                    )
                )
            key = (i for i, k in enumerate(key) if k)
        return Array(map(super().__getitem__, key))

Classes

class Array (*args)

A functional mutable sequence inheriting from the built-in list.

Constructs an Array from arguments. Nested lists, tuples and range objects are converted to Arrays, while other iterables will stored as Array elements.

Expand source code
class Array(list, L.ASeq):
    """
    A functional mutable sequence
    inheriting from the built-in list.
    """

    __slots__ = []
    __baseIterables = (list, range, tuple)

    def __init__(self, *args):
        """
        Constructs an Array from arguments.
        Nested lists, tuples and range objects are converted to
        Arrays, while other iterables will stored as Array elements.
        """
        if len(args) == 1 and isinstance(args[0], Iterable):
            args = list(args[0])

        if any(map(lambda e: isinstance(e, Array.__baseIterables), args)):
            super().__init__(self.__convert(a) for a in args)
        else:
            super().__init__(args)

    def add(self, e, inplace=False):
        """
        Element-wise addition with given scalar or sequence.
        """
        return self.__operate(operator.add, e, inplace)

    def sub(self, e, inplace=False):
        """
        Element-wise subtraction with given scalar or sequence.
        """
        return self.__operate(operator.sub, e, inplace)

    def mul(self, e, inplace=False):
        """
        Element-wise multiplication with given scalar or sequence.
        """
        return self.__operate(operator.mul, e, inplace)

    def div(self, e, inplace=False):
        """
        Element-wise division with given scalar or sequence.
        """
        return self.__operate(operator.truediv, e, inplace)

    def pow(self, e, inplace=False):
        """
        Raises elements of this Array to given power,
        or sequence of powers, element-wise.
        """
        return self.__operate(operator.pow, e, inplace)

    def mod(self, e, inplace=False):
        """
        Computes the remainder between elements in this Array
        and given scalar or sequence, element-wise.
        """
        return self.__operate(operator.mod, e, inplace)

    def bitwise_and(self, e, inplace=False):
        """
        Computes the bit-wise AND between elements in this Array
        and given scalar or sequence, element-wise.
        """
        return self.__operate(operator.and_, e, inplace)

    def bitwise_or(self, e, inplace=False):
        """
        Computes the bit-wise OR between elements in this Array
        and given scalar or sequence, element-wise.
        """
        return self.__operate(operator.or_, e, inplace)

    def abs(self, inplace=False):
        """ Element-wise absolute value. """
        a = map(abs, self)
        if inplace:
            return self.__setinplace(a, inplace)
        return Array(a)

    def sum(self, start=0):
        """ Returns the sum of the Array elements. """
        return sum(self, start)

    def product(self, start=1):
        """ Returns the product of the Array elements. """
        return reduce(lambda a, b: a * b, self, start)

    def mean(self):
        """ Returns the average of the Array elements. """
        return sum(self) / self.size

    def average(self, weights=None):
        """ Returns the weighted average of the Array elements. """
        if weights is None:
            return sum(self) / self.size
        else:
            self.__validate_seq(weights)
            return sum(self.mul(weights)) / sum(weights)

    def floor(self, inplace=False):
        """ Floors the Array elements. """
        a = map(math.floor, self)
        if inplace:
            return self.__setinplace(a, inplace)
        return Array(a)

    def ceil(self, inplace=False):
        """ Ceils the Array elements. """
        a = map(math.ceil, self)
        if inplace:
            return self.__setinplace(a, inplace)
        return Array(a)

    def round(self, d=0, inplace=False):
        """ Rounds the Array to the given number of decimals. """
        a = map(lambda e: round(e, d), self)
        if inplace:
            return self.__setinplace(a, inplace)
        return Array(a)

    def gt(self, e, inplace=False):
        """ Returns x > y element-wise """
        return self.__operate(operator.gt, e, inplace)

    def ge(self, e, inplace=False):
        """ Returns x >= y element-wise """
        return self.__operate(operator.ge, e, inplace)

    def lt(self, e, inplace=False):
        """ Returns x < y element-wise """
        return self.__operate(operator.lt, e, inplace)

    def le(self, e, inplace=False):
        """ Returns x <= y element-wise """
        return self.__operate(operator.le, e, inplace)

    def eq(self, e, inplace=False):
        """ Returns x == y element-wise """
        return self.__operate(operator.eq, e, inplace)

    def ne(self, e, inplace=False):
        """ Returns x != y element-wise """
        return self.__operate(operator.ne, e, inplace)

    def accumulate(self, func=operator.add):
        """
        Returns accumulated Array of elements using provided function.
        Defaults to accumulated sum.
        """
        return Array(itertools.accumulate(self, func))

    def clip(self, _min, _max, inplace=False):
        """
        Clip the values in the Array between the interval (`_min`, `_max`).
        """
        a = map(lambda e: max(min(e, _max), _min), self)
        if inplace:
            return self.__setinplace(a, inplace)
        return Array(a)

    def roll(self, n, inplace=False):
        """ Rolls the elements of the Array. """
        n = n % self.size
        a = self[-n:] + self[:-n]
        if inplace:
            return self.__setinplace(a, inplace)
        return a

    def cat(self, b):
        """ Concatenates a sequence to this Array. """
        return self + Array(b)

    def diff(self, n=1):
        """ Returns the n-th discrete difference of the Array. """
        if n == 1:
            return self[1:].sub(self[:-1])
        else:
            return self[1:].sub(self[:-1]).diff(n - 1)

    def difference(self, b):
        """
        Difference between this Array and another iterable.
        Returns the values in this Array that are not in sequence b.
        """
        s = set(b)
        return Array(e for e in self if e not in s)

    def setdifference(self, b):
        """
        Difference between this Array and another iterable.
        Returns the unique values in this Array that are not in sequence b.
        Does not preserve order of elements.
        """
        return Array(set(self).difference(set(b)))

    def intersect(self, b):
        """
        Intersection between this Array and another iterable.
        Returns the values that are both in this Array and sequence b.
        """
        s = set(b)
        return Array(e for e in self if e in s)

    def setintersect(self, b):
        """
        Intersection between this Array and another iterable.
        Returns the unique values that are both in this Array and sequence b.
        Does not preserve order of elements.
        """
        return Array(set(self).intersection(set(b)))

    def union(self, b):
        """
        Union of this Array and another iterable.
        Returns the values that are in either this Array or sequence b.
        """
        return self + b

    def setunion(self, b):
        """
        Union of this Array and another iterable.
        Returns the unique values that are in either this Array or sequence b.
        Does not preserve order of elements.
        """
        return Array(set(self).union(set(b)))

    def unique(self):
        """
        Selects unique values in this Array.
        Does not preserve order of elements.
        """
        return Array(set(self))

    def nunique(self):
        """ Returns the number of unique elements in the Array. """
        return len(set(self))

    def equal(self, b):
        """ Returns true this Array and given sequence have the same elements. """
        if len(self) != len(b):
            return False
        return all(self.eq(b))

    def remove(self, b, inplace=False):
        """ Removes first occurence(s) of the value(s). """
        a = self if inplace else self.copy()
        if isinstance(b, Iterable):
            for i in b:
                super(Array, a).remove(i)
        else:
            super(Array, a).remove(b)
        return a

    def remove_by_index(self, b, inplace=False):
        """ Removes the value at specified index or indices. """
        a = self if inplace else self.copy()
        if isinstance(b, Iterable):
            try:
                c = 0
                for i in b:
                    a.pop(i - c)
                    c += 1
            except TypeError:
                raise TypeError(
                    "{} object cannot be interpreted as an integer".format(
                        type(i).__name__
                    )
                ) from None
        else:
            try:
                a.pop(b)
            except TypeError:
                raise TypeError(
                    "{} object cannot be interpreted as an integer".format(
                        type(b).__name__
                    )
                ) from None
        return a

    def get(self, key, default=None):
        """
        Safe method for getting elements in the Array.
        Returns default if the index does not exist.
        """
        try:
            return self[key]
        except IndexError:
            return default

    def map(self, func, inplace=False):
        """
        Returns an Array by applying provided function to all elements of this Array.
        """
        a = map(func, self)
        if inplace:
            return self.__setinplace(a, inplace)
        return Array(a)

    def starmap(self, func):
        """
        Returns an Array by applying provided function
        to this Array with itertools.starmap
        """
        return Array(itertools.starmap(func, self))

    def parmap(self, func, processes=None, Pool=multiprocessing.Pool):
        """
        Returns an Array by applying a function to
        all elements of this Array in parallel.

        Parameters
        ----------
        func: Callable
        processes: int, optional
        Pool: Pool, optional (multiprocessing.Pool, multiprocessing.pool.ThreadPool)
        """
        with Pool(processes=processes) as pool:
            return Array(pool.map(func, self))

    def parstarmap(self, func, processes=None, Pool=multiprocessing.Pool):
        """
        Parallel starmap

        Parameters
        ----------
        func: Callable
        processes: int, optional
        Pool: Pool, optional (multiprocessing.Pool, multiprocessing.pool.ThreadPool)
        """
        with Pool(processes=processes) as pool:
            return Array(pool.starmap(func, self))

    def asyncmap(self, func, Executor=ThreadPoolExecutor):
        """
        Executes map asynchronously.
        Returns a Future object.

        Parameters
        ----------
        func: Callable
        Executor: Executor, optional (concurrent.futures.ThreadPoolExecutor, concurrent.futures.ProcessPoolExecutor)
        """
        with Executor() as executor:
            return executor.submit(self.map, func)

    def asyncstarmap(self, func, Executor=ThreadPoolExecutor):
        """
        Executes starmap asynchronously.
        Returns a Future object.

        Parameters
        ----------
        func: Callable
        Executor: Executor, optional (concurrent.futures.ThreadPoolExecutor, concurrent.futures.ProcessPoolExecutor)
        """
        with Executor() as executor:
            return executor.submit(self.starmap, func)

    def filter(self, func):
        """ Selects elements of this Array which satisfy the predicate. """
        return Array(filter(func, self))

    def forall(self, func):
        """
        Returns whether the specified predicate
        holds for all elements of this Array.
        """
        return all(map(func, self))

    def forany(self, func):
        """
        Returns whether the specified predicate
        holds for any element of this Array.
        """
        return any(map(func, self))

    def foreach(self, func):
        """ Applies `func` to each element of the Array. """
        for e in self:
            func(e)

    def reduce(self, func, init=None):
        """ Reduces the elements of this Array using the specified operator. """
        if init is not None:
            return reduce(func, self, init)
        return reduce(func, self)

    def contains(self, e):
        """ Tests whether element exists in this Array. """
        return e in self

    def index_where(self, func):
        """ Finds the index of the first element satisfying a predicate. """
        for i, v in enumerate(self):
            if func(v):
                return i
        raise ValueError("No matches")

    def indices_where(self, func):
        """ Finds all the indices of the elements satisfying a predicate. """
        return Array(i for i, v in enumerate(self) if func(v))

    def indices(self, e):
        """ Returns all the indices of provided value in this Array. """
        r = []
        o = -1
        while True:
            try:
                o = self.index(e, o + 1)
            except ValueError:
                return Array(r)
            r.append(o)

    def split(self, c):
        """
        Splits an Array into subarrays using provided argument as the delimiter element.
        """
        try:
            i = self.index(c)
            v = self[:i].unsqueeze if i != 0 else Array()
            for e in self[i + 1 :].split(c):
                if len(e) != 0:
                    v.append(e)
            return v
        except ValueError:
            return self.unsqueeze

    def split_to(self, n):
        """ Splits this Array to n equal length subarrays """
        if self.size % n != 0:
            raise ValueError("Split does not result in an equal division")
        d = self.size // n
        return Array(self[d * i : d * (i + 1)] for i in range(n))

    def split_at(self, n):
        """ Splits this Array into subarrays at specified index or indices. """
        if isinstance(n, int):
            return Array(self[:n], self[n:])
        n = Array(0, *n, self.size)
        return Array(self[n[i] : n[i + 1]] for i in range(n.size - 1))

    def chunks(self, n, drop_last=False):
        """
        Splits this Array into chunks of size n.
        If `drop_last` is True, drops the last subarray if the split
        results in an inequal division.
        """
        self.__validate_bool_arg(drop_last, "drop_last")
        fun = int if drop_last else math.ceil
        return Array(self[i * n : (i + 1) * n] for i in range(fun(self.size / n)))

    def windows(self, size, stride=1, drop_last=True):
        """
        Returns sliding windows of width `size` over the Array.
        If `drop_last` is True, drops the last subarrays that are
        shorter than the window size.
        """
        self.__validate_bool_arg(drop_last, "drop_last")
        end = (self.size - size + 1) if drop_last else self.size
        return Array(self[i : i + size] for i in range(0, end, stride))

    def takewhile(self, func):
        """ Takes the longest prefix of elements that satisfy the given predicate. """
        return Array(itertools.takewhile(func, self))

    def dropwhile(self, func):
        """ Drops the longest prefix of elements that satisfy the given predicate. """
        return Array(itertools.dropwhile(func, self))

    def groupby(self, func):
        """
        Groups this Array into an Array of Array-tuples according
        to given discriminator function.
        """
        return Array(
            (e, Array(g)) for e, g in itertools.groupby(sorted(self, key=func), func)
        )

    def maxby(self, func, **kwargs):
        """ Finds the maximum value measured by a function. """
        return max(self, key=func, **kwargs)

    def minby(self, func, **kwargs):
        """ Finds the minimum value measured by a function. """
        return min(self, key=func, **kwargs)

    def sortby(self, func, reverse=False, inplace=False):
        """
        Sorts this Array according to a function
        defining the sorting criteria.
        """
        if inplace:
            self.__validate_bool_arg(inplace, "inplace")
            super().sort(key=func, reverse=reverse)
            return self
        return Array(sorted(self, key=func, reverse=reverse))

    def argsortby(self, func, reverse=False):
        """
        Returns the indices that would sort this Array according to
        provided sorting criteria.
        """
        return self.enumerate.sortby(lambda e: func(e[1]), reverse=reverse)[:, 0]

    def sort(self, inplace=False, **kwargs):
        """ Sorts this Array. """
        if inplace:
            self.__validate_bool_arg(inplace, "inplace")
            super().sort(**kwargs)
            return self
        return Array(sorted(self, **kwargs))

    def argsort(self, reverse=False):
        """ Returns the indices that would sort this Array """
        return self.enumerate.sortby(lambda e: e[1], reverse=reverse)[:, 0]

    def reverse(self, inplace=False):
        """ Reverses this Array. """
        if inplace:
            self.__validate_bool_arg(inplace, "inplace")
            super().reverse()
            return self
        return Array(reversed(self))

    def copy(self):
        return Array(super().copy())

    def astype(self, t):
        """
        Converts the elements in this Array to given type.
        """
        return Array(map(t, self))

    def join(self, delimiter=" "):
        """
        Creates a string representation of this Array
        with elements separated with `delimiter`
        """
        return delimiter.join(str(v) for v in self)

    def append(self, e):
        """
        Appends an element to the end of this Array.
        """
        super().append(self.__convert(e))
        return self

    def prepend(self, e):
        """
        Prepends an element to the beginning of this Array.
        """
        super().insert(0, self.__convert(e))
        return self

    def extend(self, e):
        """ Extend this Array by appending elements from the iterable. """
        super().extend(Array(e))
        return self

    def extendleft(self, e):
        """ Extends this Array by prepending elements from the iterable. """
        self[0:0] = Array(e)
        return self

    def insert(self, i, e):
        """ Inserts element(s) (in place) before given index/indices. """
        if isinstance(e, Array.__baseIterables) and isinstance(
            i, Array.__baseIterables
        ):
            if len(e) != len(i):
                raise ValueError(
                    "The lengths of the sequences must match, got {} and {}".format(
                        len(i), len(e)
                    )
                )
            for ii, ei in zip(i, e):
                self.insert(ii, ei)
        else:
            super().insert(i, self.__convert(e))
        return self

    def fill(self, e, inplace=False):
        """ Replaces all elements of this Array with given object. """
        if inplace:
            return self.__setinplace(e, inplace)
        return Array([e] * self.size)

    def pad(self, n, value=0):
        """ Pads this Array with value. """
        try:
            return self + [value] * n
        except TypeError:
            raise TypeError(
                "{} object cannot be interpreted as an integer".format(type(n).__name__)
            ) from None

    def padleft(self, n, value=0):
        """ Pads this Array with value. """
        try:
            return [value] * n + self
        except TypeError:
            raise TypeError(
                "{} object cannot be interpreted as an integer".format(type(n).__name__)
            ) from None

    def pad_to(self, n, value=0):
        """
        Pads this Array with value until length of n is reached.
        """
        try:
            return self + [value] * (n - self.size)
        except TypeError:
            raise TypeError(
                "{} object cannot be interpreted as an integer".format(type(n).__name__)
            ) from None

    def padleft_to(self, n, value=0):
        """ Pads this Array with value until length of n is reached. """
        try:
            return [value] * (n - self.size) + self
        except TypeError:
            raise TypeError(
                "{} object cannot be interpreted as an integer".format(type(n).__name__)
            ) from None

    def zip(self, *args):
        return Array(zip(self, *args))

    def unzip(self):
        """
        'Unzips' nested Arrays by unpacking its elements into a zip.

        >>> Array((1, "a"), (2, "b")).unzip()
        Array(Array(1, 2), Array('a', 'b'))
        """
        if not all(map(lambda e: isinstance(e, Iterable), self)):
            raise TypeError("Array elements must support iteration")
        return Array(zip(*self))

    def zip_all(self, *args, default=None):
        """
        Zips the sequences. If the iterables are
        of uneven length, missing values are filled with default value.
        """
        return Array(itertools.zip_longest(self, *args, fillvalue=default))

    def all(self):
        """ Returns true if bool(e) is True for all elements in this Array. """
        return all(self)

    def any(self):
        """ Returns true if bool(e) is True for any element e in this Array. """
        return any(self)

    def max(self, **kwargs):
        return max(self, **kwargs)

    def argmax(self):
        """ Returns the index of the maximum value """
        return max(self.enumerate, key=lambda e: e[1])[0]

    def min(self, **kwargs):
        return min(self, **kwargs)

    def argmin(self):
        """ Returns the index of the minimum value """
        return min(self.enumerate, key=lambda e: e[1])[0]

    @property
    def head(self):
        """ Selects the first element of this Array. """
        return self[0]

    def head_option(self, default=None):
        """
        Selects the first element of this Array if it has one,
        otherwise returns default.
        """
        return self.get(0, default)

    @property
    def last(self):
        """ Selects the last element of this Array. """
        return self[-1]

    def last_option(self, default=None):
        """
        Selects the last element of this Array if it has one,
        otherwise returns default.
        """
        return self.get(-1, default)

    @property
    def init(self):
        """ Selects the rest of this Array without its last element. """
        return self[:-1]

    @property
    def tail(self):
        """ Selects the rest of this Array without its first element. """
        return self[1:]

    @property
    def isempty(self):
        """ Returns whether this Array is empty. """
        return self.size == 0

    @property
    def nonempty(self):
        """ Returns whether this Array is not empty. """
        return self.size != 0

    def isfinite(self):
        """
        Tests element-wise whether the elements are neither infinity nor NaN.
        """
        return Array(map(math.isfinite, self))

    @property
    def length(self):
        """ Number of elements in this Array. """
        return self.__len__()

    @property
    def size(self):
        """ Number of elements in this Array. """
        return self.__len__()

    def int(self):
        """ Converts elements in this Array to integers. """
        try:
            return Array(map(lambda e: ord(e) if isinstance(e, str) else int(e), self))
        except TypeError:
            raise TypeError("Expected an Array of numbers or characters") from None

    def float(self):
        """ Converts elements in this Array to floats. """
        return Array(map(float, self))

    def bool(self):
        """ Converts elements in this Array to booleans. """
        return Array(map(bool, self))

    def char(self):
        """ Converts an Array of integers to chars. """
        return Array(map(chr, self))

    def to_str(self):
        """
        Creates a string representation of the Array.
        See Array.join for more functionality.
        """
        return "".join(str(v) for v in self)

    def to_tuple(self):
        """ Returns a copy of the Array as an tuple. """
        return tuple(self.copy())

    def to_set(self):
        """ Returns set of the Array elements. Order is not preserved. """
        return set(self)

    def to_iter(self):
        """ Returns an iterator for the Array."""
        for e in self:
            yield e

    def to_dict(self):
        """ Creates a dictionary from an Array of Arrays / tuples. """
        return dict(self)

    @property
    def squeeze(self):
        """
        Returns the Array with the same elements, but with
        outermost singleton dimension removed (if exists).
        """
        if isinstance(self.head_option(), Array.__baseIterables) and self.length == 1:
            return self[0]
        else:
            return self

    @property
    def unsqueeze(self):
        """
        Returns the Array with the same elements wrapped in a Array.
        """
        return Array([self])

    @property
    def flatten(self):
        """ Returns the Array collapsed into one dimension. """
        r = Array(
            e
            for s in self
            for e in (s if isinstance(s, Array.__baseIterables) else [s])
        )
        if any(map(lambda e: isinstance(e, Array.__baseIterables), r)):
            return r.flatten
        return r

    @property
    def range(self):
        """ Returns the indices of the Array"""
        return Array(range(self.size))

    @property
    def enumerate(self):
        """ Zips the Array with its indices """
        return Array(enumerate(self))

    @staticmethod
    def zeros(n):
        """ Returns a zero-filled Array of given length. """
        try:
            return Array([0] * n)
        except TypeError:
            raise TypeError(
                "{} object cannot be interpreted as an integer".format(type(n).__name__)
            ) from None

    @staticmethod
    def arange(*args):
        """
        Returns an Array of evenly spaced values within given interval

        Parameters
        ----------
        start: number, optional
        end: number
        step: number, optional
        """
        _len = len(args)
        if _len == 0:
            raise TypeError("Expected at least one argument")
        elif _len > 3:
            raise TypeError("Expected at most 3 arguments")
        elif _len == 1:
            return Array(range(math.ceil(args[0])))
        start, end, step = args if _len == 3 else args + (1,)
        return Array(start + step * i for i in range(math.ceil((end - start) / step)))

    @staticmethod
    def linspace(start, stop, num=50, endpoint=True):
        """
        Returns evenly spaced Array over a specified interval.

        Parameters
        ----------
        start: number
        stop: number
        num: int, optional
        endpoint : bool, optional
        """
        Array.__validate_bool_arg(None, endpoint, "endpoint")
        step = (stop - start) / max(num - bool(endpoint), 1)
        return Array(start + step * i for i in range(num))

    @staticmethod
    def logspace(start, stop, num=50, base=10, endpoint=True):
        """
        Returns Array spaced evenly on a log scale.

        Parameters
        ----------
        start: number
        stop: number
        num: int, optional
        base: float, optional
        endpoint: bool, optional
        """
        Array.__validate_bool_arg(None, endpoint, "endpoint")
        return base ** Array.linspace(start, stop, num, endpoint)

    def __convert(self, e):
        return Array(e) if isinstance(e, Array.__baseIterables) else e

    def __validate_index(self, i):
        if not isinstance(i, (int, slice)):
            if not isinstance(i, Sequence) or not all(
                map(lambda e: isinstance(e, (bool, int, slice)), i)
            ):
                raise TypeError(
                    "Only integers, slices and 1d integer or boolean Arrays are valid indices"
                )

    def __validate_setelem(self, i, e):
        if isinstance(e, Iterable):
            if len(i) != len(e):
                raise ValueError(
                    "Expected Array of size {}, got {}".format(len(i), len(e))
                )
            return iter(e)
        else:
            return itertools.repeat(e)

    def __validate_seq(self, e):
        if len(e) != self.size:
            raise ValueError(
                "The lengths of the sequences must match, got {} and {}".format(
                    self.size, len(e)
                )
            )

    def __validate_bool_arg(self, value, name):
        if not isinstance(value, bool):
            raise ValueError(f"Expected type bool for {name} argument")

    def __setinplace(self, s, arg):
        self.__validate_bool_arg(arg, "inplace")
        self[:] = s
        return self

    def __map(self, f, e):
        if isinstance(e, Iterable):
            return map(f, self, e)
        return map(f, self, itertools.repeat(e))

    def __operate(self, op, e, inplace):
        self.__validate_bool_arg(inplace, "inplace")
        a = self.__map(op, e)
        if inplace:
            self[:] = a
            return self
        return Array(a)

    def __repr__(self):
        return "Array" + "(" + super().__repr__()[1:-1] + ")"

    def __add__(self, b):
        if isinstance(b, Array.__baseIterables):
            return Array(super().__add__(Array(b)))
        else:
            raise TypeError(f"Can not concatenate {type(b).__name__} to Array")

    def __iadd__(self, b):
        if isinstance(b, Array.__baseIterables):
            super().__iadd__(b)
            return self
        else:
            raise TypeError(f"Can not concatenate {type(b).__name__} to Array")

    def __radd__(self, b):
        if isinstance(b, Array.__baseIterables):
            return Array(b) + self
        else:
            raise TypeError(f"Can not concatenate {type(b).__name__} to Array")

    def __pow__(self, b):
        return self.pow(b)

    def __rpow__(self, b):
        if isinstance(b, Array.__baseIterables):
            return Array(b).pow(self)
        return Array([b] * self.size).pow(self)

    def __gt__(self, e):
        return self.__operate(operator.gt, e, False)

    def __ge__(self, e):
        return self.__operate(operator.ge, e, False)

    def __lt__(self, e):
        return self.__operate(operator.lt, e, False)

    def __le__(self, e):
        return self.__operate(operator.le, e, False)

    def __eq__(self, e):
        return self.__operate(operator.eq, e, False)

    def __ne__(self, e):
        return self.__operate(operator.ne, e, False)

    def __and__(self, e):
        return self.__operate(operator.and_, e, False)

    def __or__(self, e):
        return self.__operate(operator.or_, e, False)

    def __neg__(self):
        return Array(map(operator.neg, self))

    def __invert__(self):
        if all(map(lambda e: isinstance(e, bool), self)):
            return Array(map(lambda e: not e, self))
        return Array(map(operator.inv, self))

    def __hash__(self):
        return hash(self.to_tuple())

    def __bool__(self):
        if self.__len__() == 0:
            warnings.warn(
                "The truth value of an empty Array is ambiguous. Use `Array.nonEmpty` to check that Array is not empty",
                UserWarning,
            )
        return all(self)

    def __setitem__(self, key, e):
        self.__validate_index(key)
        if isinstance(key, tuple):
            if len(key) == 1:
                key = key[0]
            else:
                if isinstance(key[0], int):
                    self[key[0]][key[1:]] = e
                    return
                try:
                    idx = range(*key[0].indices(self.size))
                    for ic in idx:
                        self[ic][key[1:]]
                    for ic, ie in zip(idx, self.__validate_setelem(idx, e)):
                        self[ic][key[1:]] = ie
                except TypeError:
                    raise IndexError("Too many indices for the Array") from None
                return
        if isinstance(key, int):
            super().__setitem__(key, self.__convert(e))
            return
        if isinstance(key, Sequence):
            for _i, _e in zip(key, self.__validate_setelem(key, e)):
                super().__setitem__(_i, _e)
            return
        if isinstance(e, Iterable):
            e = self.__convert(e)
        else:
            e = [e] * len(range(*key.indices(self.size)))
        super().__setitem__(key, e)

    def __getitem__(self, key):
        self.__validate_index(key)
        if isinstance(key, tuple):
            if len(key) == 1:
                key = key[0]
            else:
                if isinstance(key[0], int):
                    return self[key[0]][key[1:]]
                try:
                    return Array(e[key[1:]] for e in super().__getitem__(key[0]))
                except TypeError:
                    raise IndexError("Too many indices for the Array") from None
        if isinstance(key, int):
            return super().__getitem__(key)
        if isinstance(key, slice):
            return Array(super().__getitem__(key))
        if all(map(lambda k: isinstance(k, bool), key)):
            if len(key) != self.size:
                raise IndexError(
                    "Expected boolean Array of size {}, got {}".format(
                        self.size, len(key)
                    )
                )
            key = (i for i, k in enumerate(key) if k)
        return Array(map(super().__getitem__, key))

Ancestors

  • builtins.list
  • ASeq

Static methods

def arange(*args)

Returns an Array of evenly spaced values within given interval

Parameters

start : number, optional
 
end : number
 
step : number, optional
 
Expand source code
@staticmethod
def arange(*args):
    """
    Returns an Array of evenly spaced values within given interval

    Parameters
    ----------
    start: number, optional
    end: number
    step: number, optional
    """
    _len = len(args)
    if _len == 0:
        raise TypeError("Expected at least one argument")
    elif _len > 3:
        raise TypeError("Expected at most 3 arguments")
    elif _len == 1:
        return Array(range(math.ceil(args[0])))
    start, end, step = args if _len == 3 else args + (1,)
    return Array(start + step * i for i in range(math.ceil((end - start) / step)))
def linspace(start, stop, num=50, endpoint=True)

Returns evenly spaced Array over a specified interval.

Parameters

start : number
 
stop : number
 
num : int, optional
 
endpoint : bool, optional
 
Expand source code
@staticmethod
def linspace(start, stop, num=50, endpoint=True):
    """
    Returns evenly spaced Array over a specified interval.

    Parameters
    ----------
    start: number
    stop: number
    num: int, optional
    endpoint : bool, optional
    """
    Array.__validate_bool_arg(None, endpoint, "endpoint")
    step = (stop - start) / max(num - bool(endpoint), 1)
    return Array(start + step * i for i in range(num))
def logspace(start, stop, num=50, base=10, endpoint=True)

Returns Array spaced evenly on a log scale.

Parameters

start : number
 
stop : number
 
num : int, optional
 
base : float, optional
 
endpoint : bool, optional
 
Expand source code
@staticmethod
def logspace(start, stop, num=50, base=10, endpoint=True):
    """
    Returns Array spaced evenly on a log scale.

    Parameters
    ----------
    start: number
    stop: number
    num: int, optional
    base: float, optional
    endpoint: bool, optional
    """
    Array.__validate_bool_arg(None, endpoint, "endpoint")
    return base ** Array.linspace(start, stop, num, endpoint)
def zeros(n)

Returns a zero-filled Array of given length.

Expand source code
@staticmethod
def zeros(n):
    """ Returns a zero-filled Array of given length. """
    try:
        return Array([0] * n)
    except TypeError:
        raise TypeError(
            "{} object cannot be interpreted as an integer".format(type(n).__name__)
        ) from None

Instance variables

var enumerate

Zips the Array with its indices

Expand source code
@property
def enumerate(self):
    """ Zips the Array with its indices """
    return Array(enumerate(self))
var flatten

Returns the Array collapsed into one dimension.

Expand source code
@property
def flatten(self):
    """ Returns the Array collapsed into one dimension. """
    r = Array(
        e
        for s in self
        for e in (s if isinstance(s, Array.__baseIterables) else [s])
    )
    if any(map(lambda e: isinstance(e, Array.__baseIterables), r)):
        return r.flatten
    return r
var head

Selects the first element of this Array.

Expand source code
@property
def head(self):
    """ Selects the first element of this Array. """
    return self[0]
var init

Selects the rest of this Array without its last element.

Expand source code
@property
def init(self):
    """ Selects the rest of this Array without its last element. """
    return self[:-1]
var isempty

Returns whether this Array is empty.

Expand source code
@property
def isempty(self):
    """ Returns whether this Array is empty. """
    return self.size == 0
var last

Selects the last element of this Array.

Expand source code
@property
def last(self):
    """ Selects the last element of this Array. """
    return self[-1]
var length

Number of elements in this Array.

Expand source code
@property
def length(self):
    """ Number of elements in this Array. """
    return self.__len__()
var nonempty

Returns whether this Array is not empty.

Expand source code
@property
def nonempty(self):
    """ Returns whether this Array is not empty. """
    return self.size != 0
var range

Returns the indices of the Array

Expand source code
@property
def range(self):
    """ Returns the indices of the Array"""
    return Array(range(self.size))
var size

Number of elements in this Array.

Expand source code
@property
def size(self):
    """ Number of elements in this Array. """
    return self.__len__()
var squeeze

Returns the Array with the same elements, but with outermost singleton dimension removed (if exists).

Expand source code
@property
def squeeze(self):
    """
    Returns the Array with the same elements, but with
    outermost singleton dimension removed (if exists).
    """
    if isinstance(self.head_option(), Array.__baseIterables) and self.length == 1:
        return self[0]
    else:
        return self
var tail

Selects the rest of this Array without its first element.

Expand source code
@property
def tail(self):
    """ Selects the rest of this Array without its first element. """
    return self[1:]
var unsqueeze

Returns the Array with the same elements wrapped in a Array.

Expand source code
@property
def unsqueeze(self):
    """
    Returns the Array with the same elements wrapped in a Array.
    """
    return Array([self])

Methods

def abs(self, inplace=False)

Element-wise absolute value.

Expand source code
def abs(self, inplace=False):
    """ Element-wise absolute value. """
    a = map(abs, self)
    if inplace:
        return self.__setinplace(a, inplace)
    return Array(a)
def accumulate(self, func=<built-in function add>)

Returns accumulated Array of elements using provided function. Defaults to accumulated sum.

Expand source code
def accumulate(self, func=operator.add):
    """
    Returns accumulated Array of elements using provided function.
    Defaults to accumulated sum.
    """
    return Array(itertools.accumulate(self, func))
def add(self, e, inplace=False)

Element-wise addition with given scalar or sequence.

Expand source code
def add(self, e, inplace=False):
    """
    Element-wise addition with given scalar or sequence.
    """
    return self.__operate(operator.add, e, inplace)
def all(self)

Returns true if bool(e) is True for all elements in this Array.

Expand source code
def all(self):
    """ Returns true if bool(e) is True for all elements in this Array. """
    return all(self)
def any(self)

Returns true if bool(e) is True for any element e in this Array.

Expand source code
def any(self):
    """ Returns true if bool(e) is True for any element e in this Array. """
    return any(self)
def append(self, e)

Appends an element to the end of this Array.

Expand source code
def append(self, e):
    """
    Appends an element to the end of this Array.
    """
    super().append(self.__convert(e))
    return self
def argmax(self)

Returns the index of the maximum value

Expand source code
def argmax(self):
    """ Returns the index of the maximum value """
    return max(self.enumerate, key=lambda e: e[1])[0]
def argmin(self)

Returns the index of the minimum value

Expand source code
def argmin(self):
    """ Returns the index of the minimum value """
    return min(self.enumerate, key=lambda e: e[1])[0]
def argsort(self, reverse=False)

Returns the indices that would sort this Array

Expand source code
def argsort(self, reverse=False):
    """ Returns the indices that would sort this Array """
    return self.enumerate.sortby(lambda e: e[1], reverse=reverse)[:, 0]
def argsortby(self, func, reverse=False)

Returns the indices that would sort this Array according to provided sorting criteria.

Expand source code
def argsortby(self, func, reverse=False):
    """
    Returns the indices that would sort this Array according to
    provided sorting criteria.
    """
    return self.enumerate.sortby(lambda e: func(e[1]), reverse=reverse)[:, 0]
def astype(self, t)

Converts the elements in this Array to given type.

Expand source code
def astype(self, t):
    """
    Converts the elements in this Array to given type.
    """
    return Array(map(t, self))
def asyncmap(self, func, Executor=concurrent.futures.thread.ThreadPoolExecutor)

Executes map asynchronously. Returns a Future object.

Parameters

func : Callable
 
Executor : Executor, optional (concurrent.futures.ThreadPoolExecutor, concurrent.futures.ProcessPoolExecutor)
 
Expand source code
def asyncmap(self, func, Executor=ThreadPoolExecutor):
    """
    Executes map asynchronously.
    Returns a Future object.

    Parameters
    ----------
    func: Callable
    Executor: Executor, optional (concurrent.futures.ThreadPoolExecutor, concurrent.futures.ProcessPoolExecutor)
    """
    with Executor() as executor:
        return executor.submit(self.map, func)
def asyncstarmap(self, func, Executor=concurrent.futures.thread.ThreadPoolExecutor)

Executes starmap asynchronously. Returns a Future object.

Parameters

func : Callable
 
Executor : Executor, optional (concurrent.futures.ThreadPoolExecutor, concurrent.futures.ProcessPoolExecutor)
 
Expand source code
def asyncstarmap(self, func, Executor=ThreadPoolExecutor):
    """
    Executes starmap asynchronously.
    Returns a Future object.

    Parameters
    ----------
    func: Callable
    Executor: Executor, optional (concurrent.futures.ThreadPoolExecutor, concurrent.futures.ProcessPoolExecutor)
    """
    with Executor() as executor:
        return executor.submit(self.starmap, func)
def average(self, weights=None)

Returns the weighted average of the Array elements.

Expand source code
def average(self, weights=None):
    """ Returns the weighted average of the Array elements. """
    if weights is None:
        return sum(self) / self.size
    else:
        self.__validate_seq(weights)
        return sum(self.mul(weights)) / sum(weights)
def bitwise_and(self, e, inplace=False)

Computes the bit-wise AND between elements in this Array and given scalar or sequence, element-wise.

Expand source code
def bitwise_and(self, e, inplace=False):
    """
    Computes the bit-wise AND between elements in this Array
    and given scalar or sequence, element-wise.
    """
    return self.__operate(operator.and_, e, inplace)
def bitwise_or(self, e, inplace=False)

Computes the bit-wise OR between elements in this Array and given scalar or sequence, element-wise.

Expand source code
def bitwise_or(self, e, inplace=False):
    """
    Computes the bit-wise OR between elements in this Array
    and given scalar or sequence, element-wise.
    """
    return self.__operate(operator.or_, e, inplace)
def bool(self)

Converts elements in this Array to booleans.

Expand source code
def bool(self):
    """ Converts elements in this Array to booleans. """
    return Array(map(bool, self))
def cat(self, b)

Concatenates a sequence to this Array.

Expand source code
def cat(self, b):
    """ Concatenates a sequence to this Array. """
    return self + Array(b)
def ceil(self, inplace=False)

Ceils the Array elements.

Expand source code
def ceil(self, inplace=False):
    """ Ceils the Array elements. """
    a = map(math.ceil, self)
    if inplace:
        return self.__setinplace(a, inplace)
    return Array(a)
def char(self)

Converts an Array of integers to chars.

Expand source code
def char(self):
    """ Converts an Array of integers to chars. """
    return Array(map(chr, self))
def chunks(self, n, drop_last=False)

Splits this Array into chunks of size n. If drop_last is True, drops the last subarray if the split results in an inequal division.

Expand source code
def chunks(self, n, drop_last=False):
    """
    Splits this Array into chunks of size n.
    If `drop_last` is True, drops the last subarray if the split
    results in an inequal division.
    """
    self.__validate_bool_arg(drop_last, "drop_last")
    fun = int if drop_last else math.ceil
    return Array(self[i * n : (i + 1) * n] for i in range(fun(self.size / n)))
def clip(self, _min, _max, inplace=False)

Clip the values in the Array between the interval (_min, _max).

Expand source code
def clip(self, _min, _max, inplace=False):
    """
    Clip the values in the Array between the interval (`_min`, `_max`).
    """
    a = map(lambda e: max(min(e, _max), _min), self)
    if inplace:
        return self.__setinplace(a, inplace)
    return Array(a)
def contains(self, e)

Tests whether element exists in this Array.

Expand source code
def contains(self, e):
    """ Tests whether element exists in this Array. """
    return e in self
def copy(self)

Return a shallow copy of the list.

Expand source code
def copy(self):
    return Array(super().copy())
def diff(self, n=1)

Returns the n-th discrete difference of the Array.

Expand source code
def diff(self, n=1):
    """ Returns the n-th discrete difference of the Array. """
    if n == 1:
        return self[1:].sub(self[:-1])
    else:
        return self[1:].sub(self[:-1]).diff(n - 1)
def difference(self, b)

Difference between this Array and another iterable. Returns the values in this Array that are not in sequence b.

Expand source code
def difference(self, b):
    """
    Difference between this Array and another iterable.
    Returns the values in this Array that are not in sequence b.
    """
    s = set(b)
    return Array(e for e in self if e not in s)
def div(self, e, inplace=False)

Element-wise division with given scalar or sequence.

Expand source code
def div(self, e, inplace=False):
    """
    Element-wise division with given scalar or sequence.
    """
    return self.__operate(operator.truediv, e, inplace)
def dropwhile(self, func)

Drops the longest prefix of elements that satisfy the given predicate.

Expand source code
def dropwhile(self, func):
    """ Drops the longest prefix of elements that satisfy the given predicate. """
    return Array(itertools.dropwhile(func, self))
def eq(self, e, inplace=False)

Returns x == y element-wise

Expand source code
def eq(self, e, inplace=False):
    """ Returns x == y element-wise """
    return self.__operate(operator.eq, e, inplace)
def equal(self, b)

Returns true this Array and given sequence have the same elements.

Expand source code
def equal(self, b):
    """ Returns true this Array and given sequence have the same elements. """
    if len(self) != len(b):
        return False
    return all(self.eq(b))
def extend(self, e)

Extend this Array by appending elements from the iterable.

Expand source code
def extend(self, e):
    """ Extend this Array by appending elements from the iterable. """
    super().extend(Array(e))
    return self
def extendleft(self, e)

Extends this Array by prepending elements from the iterable.

Expand source code
def extendleft(self, e):
    """ Extends this Array by prepending elements from the iterable. """
    self[0:0] = Array(e)
    return self
def fill(self, e, inplace=False)

Replaces all elements of this Array with given object.

Expand source code
def fill(self, e, inplace=False):
    """ Replaces all elements of this Array with given object. """
    if inplace:
        return self.__setinplace(e, inplace)
    return Array([e] * self.size)
def filter(self, func)

Selects elements of this Array which satisfy the predicate.

Expand source code
def filter(self, func):
    """ Selects elements of this Array which satisfy the predicate. """
    return Array(filter(func, self))
def float(self)

Converts elements in this Array to floats.

Expand source code
def float(self):
    """ Converts elements in this Array to floats. """
    return Array(map(float, self))
def floor(self, inplace=False)

Floors the Array elements.

Expand source code
def floor(self, inplace=False):
    """ Floors the Array elements. """
    a = map(math.floor, self)
    if inplace:
        return self.__setinplace(a, inplace)
    return Array(a)
def forall(self, func)

Returns whether the specified predicate holds for all elements of this Array.

Expand source code
def forall(self, func):
    """
    Returns whether the specified predicate
    holds for all elements of this Array.
    """
    return all(map(func, self))
def forany(self, func)

Returns whether the specified predicate holds for any element of this Array.

Expand source code
def forany(self, func):
    """
    Returns whether the specified predicate
    holds for any element of this Array.
    """
    return any(map(func, self))
def foreach(self, func)

Applies func to each element of the Array.

Expand source code
def foreach(self, func):
    """ Applies `func` to each element of the Array. """
    for e in self:
        func(e)
def ge(self, e, inplace=False)

Returns x >= y element-wise

Expand source code
def ge(self, e, inplace=False):
    """ Returns x >= y element-wise """
    return self.__operate(operator.ge, e, inplace)
def get(self, key, default=None)

Safe method for getting elements in the Array. Returns default if the index does not exist.

Expand source code
def get(self, key, default=None):
    """
    Safe method for getting elements in the Array.
    Returns default if the index does not exist.
    """
    try:
        return self[key]
    except IndexError:
        return default
def groupby(self, func)

Groups this Array into an Array of Array-tuples according to given discriminator function.

Expand source code
def groupby(self, func):
    """
    Groups this Array into an Array of Array-tuples according
    to given discriminator function.
    """
    return Array(
        (e, Array(g)) for e, g in itertools.groupby(sorted(self, key=func), func)
    )
def gt(self, e, inplace=False)

Returns x > y element-wise

Expand source code
def gt(self, e, inplace=False):
    """ Returns x > y element-wise """
    return self.__operate(operator.gt, e, inplace)
def head_option(self, default=None)

Selects the first element of this Array if it has one, otherwise returns default.

Expand source code
def head_option(self, default=None):
    """
    Selects the first element of this Array if it has one,
    otherwise returns default.
    """
    return self.get(0, default)
def index_where(self, func)

Finds the index of the first element satisfying a predicate.

Expand source code
def index_where(self, func):
    """ Finds the index of the first element satisfying a predicate. """
    for i, v in enumerate(self):
        if func(v):
            return i
    raise ValueError("No matches")
def indices(self, e)

Returns all the indices of provided value in this Array.

Expand source code
def indices(self, e):
    """ Returns all the indices of provided value in this Array. """
    r = []
    o = -1
    while True:
        try:
            o = self.index(e, o + 1)
        except ValueError:
            return Array(r)
        r.append(o)
def indices_where(self, func)

Finds all the indices of the elements satisfying a predicate.

Expand source code
def indices_where(self, func):
    """ Finds all the indices of the elements satisfying a predicate. """
    return Array(i for i, v in enumerate(self) if func(v))
def insert(self, i, e)

Inserts element(s) (in place) before given index/indices.

Expand source code
def insert(self, i, e):
    """ Inserts element(s) (in place) before given index/indices. """
    if isinstance(e, Array.__baseIterables) and isinstance(
        i, Array.__baseIterables
    ):
        if len(e) != len(i):
            raise ValueError(
                "The lengths of the sequences must match, got {} and {}".format(
                    len(i), len(e)
                )
            )
        for ii, ei in zip(i, e):
            self.insert(ii, ei)
    else:
        super().insert(i, self.__convert(e))
    return self
def int(self)

Converts elements in this Array to integers.

Expand source code
def int(self):
    """ Converts elements in this Array to integers. """
    try:
        return Array(map(lambda e: ord(e) if isinstance(e, str) else int(e), self))
    except TypeError:
        raise TypeError("Expected an Array of numbers or characters") from None
def intersect(self, b)

Intersection between this Array and another iterable. Returns the values that are both in this Array and sequence b.

Expand source code
def intersect(self, b):
    """
    Intersection between this Array and another iterable.
    Returns the values that are both in this Array and sequence b.
    """
    s = set(b)
    return Array(e for e in self if e in s)
def isfinite(self)

Tests element-wise whether the elements are neither infinity nor NaN.

Expand source code
def isfinite(self):
    """
    Tests element-wise whether the elements are neither infinity nor NaN.
    """
    return Array(map(math.isfinite, self))
def join(self, delimiter=' ')

Creates a string representation of this Array with elements separated with delimiter

Expand source code
def join(self, delimiter=" "):
    """
    Creates a string representation of this Array
    with elements separated with `delimiter`
    """
    return delimiter.join(str(v) for v in self)
def last_option(self, default=None)

Selects the last element of this Array if it has one, otherwise returns default.

Expand source code
def last_option(self, default=None):
    """
    Selects the last element of this Array if it has one,
    otherwise returns default.
    """
    return self.get(-1, default)
def le(self, e, inplace=False)

Returns x <= y element-wise

Expand source code
def le(self, e, inplace=False):
    """ Returns x <= y element-wise """
    return self.__operate(operator.le, e, inplace)
def lt(self, e, inplace=False)

Returns x < y element-wise

Expand source code
def lt(self, e, inplace=False):
    """ Returns x < y element-wise """
    return self.__operate(operator.lt, e, inplace)
def map(self, func, inplace=False)

Returns an Array by applying provided function to all elements of this Array.

Expand source code
def map(self, func, inplace=False):
    """
    Returns an Array by applying provided function to all elements of this Array.
    """
    a = map(func, self)
    if inplace:
        return self.__setinplace(a, inplace)
    return Array(a)
def max(self, **kwargs)
Expand source code
def max(self, **kwargs):
    return max(self, **kwargs)
def maxby(self, func, **kwargs)

Finds the maximum value measured by a function.

Expand source code
def maxby(self, func, **kwargs):
    """ Finds the maximum value measured by a function. """
    return max(self, key=func, **kwargs)
def mean(self)

Returns the average of the Array elements.

Expand source code
def mean(self):
    """ Returns the average of the Array elements. """
    return sum(self) / self.size
def min(self, **kwargs)
Expand source code
def min(self, **kwargs):
    return min(self, **kwargs)
def minby(self, func, **kwargs)

Finds the minimum value measured by a function.

Expand source code
def minby(self, func, **kwargs):
    """ Finds the minimum value measured by a function. """
    return min(self, key=func, **kwargs)
def mod(self, e, inplace=False)

Computes the remainder between elements in this Array and given scalar or sequence, element-wise.

Expand source code
def mod(self, e, inplace=False):
    """
    Computes the remainder between elements in this Array
    and given scalar or sequence, element-wise.
    """
    return self.__operate(operator.mod, e, inplace)
def mul(self, e, inplace=False)

Element-wise multiplication with given scalar or sequence.

Expand source code
def mul(self, e, inplace=False):
    """
    Element-wise multiplication with given scalar or sequence.
    """
    return self.__operate(operator.mul, e, inplace)
def ne(self, e, inplace=False)

Returns x != y element-wise

Expand source code
def ne(self, e, inplace=False):
    """ Returns x != y element-wise """
    return self.__operate(operator.ne, e, inplace)
def nunique(self)

Returns the number of unique elements in the Array.

Expand source code
def nunique(self):
    """ Returns the number of unique elements in the Array. """
    return len(set(self))
def pad(self, n, value=0)

Pads this Array with value.

Expand source code
def pad(self, n, value=0):
    """ Pads this Array with value. """
    try:
        return self + [value] * n
    except TypeError:
        raise TypeError(
            "{} object cannot be interpreted as an integer".format(type(n).__name__)
        ) from None
def pad_to(self, n, value=0)

Pads this Array with value until length of n is reached.

Expand source code
def pad_to(self, n, value=0):
    """
    Pads this Array with value until length of n is reached.
    """
    try:
        return self + [value] * (n - self.size)
    except TypeError:
        raise TypeError(
            "{} object cannot be interpreted as an integer".format(type(n).__name__)
        ) from None
def padleft(self, n, value=0)

Pads this Array with value.

Expand source code
def padleft(self, n, value=0):
    """ Pads this Array with value. """
    try:
        return [value] * n + self
    except TypeError:
        raise TypeError(
            "{} object cannot be interpreted as an integer".format(type(n).__name__)
        ) from None
def padleft_to(self, n, value=0)

Pads this Array with value until length of n is reached.

Expand source code
def padleft_to(self, n, value=0):
    """ Pads this Array with value until length of n is reached. """
    try:
        return [value] * (n - self.size) + self
    except TypeError:
        raise TypeError(
            "{} object cannot be interpreted as an integer".format(type(n).__name__)
        ) from None
def parmap(self, func, processes=None, Pool=<bound method BaseContext.Pool of <multiprocessing.context.DefaultContext object>>)

Returns an Array by applying a function to all elements of this Array in parallel.

Parameters

func : Callable
 
processes : int, optional
 
Pool : Pool, optional (multiprocessing.Pool, multiprocessing.pool.ThreadPool)
 
Expand source code
def parmap(self, func, processes=None, Pool=multiprocessing.Pool):
    """
    Returns an Array by applying a function to
    all elements of this Array in parallel.

    Parameters
    ----------
    func: Callable
    processes: int, optional
    Pool: Pool, optional (multiprocessing.Pool, multiprocessing.pool.ThreadPool)
    """
    with Pool(processes=processes) as pool:
        return Array(pool.map(func, self))
def parstarmap(self, func, processes=None, Pool=<bound method BaseContext.Pool of <multiprocessing.context.DefaultContext object>>)

Parallel starmap

Parameters

func : Callable
 
processes : int, optional
 
Pool : Pool, optional (multiprocessing.Pool, multiprocessing.pool.ThreadPool)
 
Expand source code
def parstarmap(self, func, processes=None, Pool=multiprocessing.Pool):
    """
    Parallel starmap

    Parameters
    ----------
    func: Callable
    processes: int, optional
    Pool: Pool, optional (multiprocessing.Pool, multiprocessing.pool.ThreadPool)
    """
    with Pool(processes=processes) as pool:
        return Array(pool.starmap(func, self))
def pow(self, e, inplace=False)

Raises elements of this Array to given power, or sequence of powers, element-wise.

Expand source code
def pow(self, e, inplace=False):
    """
    Raises elements of this Array to given power,
    or sequence of powers, element-wise.
    """
    return self.__operate(operator.pow, e, inplace)
def prepend(self, e)

Prepends an element to the beginning of this Array.

Expand source code
def prepend(self, e):
    """
    Prepends an element to the beginning of this Array.
    """
    super().insert(0, self.__convert(e))
    return self
def product(self, start=1)

Returns the product of the Array elements.

Expand source code
def product(self, start=1):
    """ Returns the product of the Array elements. """
    return reduce(lambda a, b: a * b, self, start)
def reduce(self, func, init=None)

Reduces the elements of this Array using the specified operator.

Expand source code
def reduce(self, func, init=None):
    """ Reduces the elements of this Array using the specified operator. """
    if init is not None:
        return reduce(func, self, init)
    return reduce(func, self)
def remove(self, b, inplace=False)

Removes first occurence(s) of the value(s).

Expand source code
def remove(self, b, inplace=False):
    """ Removes first occurence(s) of the value(s). """
    a = self if inplace else self.copy()
    if isinstance(b, Iterable):
        for i in b:
            super(Array, a).remove(i)
    else:
        super(Array, a).remove(b)
    return a
def remove_by_index(self, b, inplace=False)

Removes the value at specified index or indices.

Expand source code
def remove_by_index(self, b, inplace=False):
    """ Removes the value at specified index or indices. """
    a = self if inplace else self.copy()
    if isinstance(b, Iterable):
        try:
            c = 0
            for i in b:
                a.pop(i - c)
                c += 1
        except TypeError:
            raise TypeError(
                "{} object cannot be interpreted as an integer".format(
                    type(i).__name__
                )
            ) from None
    else:
        try:
            a.pop(b)
        except TypeError:
            raise TypeError(
                "{} object cannot be interpreted as an integer".format(
                    type(b).__name__
                )
            ) from None
    return a
def reverse(self, inplace=False)

Reverses this Array.

Expand source code
def reverse(self, inplace=False):
    """ Reverses this Array. """
    if inplace:
        self.__validate_bool_arg(inplace, "inplace")
        super().reverse()
        return self
    return Array(reversed(self))
def roll(self, n, inplace=False)

Rolls the elements of the Array.

Expand source code
def roll(self, n, inplace=False):
    """ Rolls the elements of the Array. """
    n = n % self.size
    a = self[-n:] + self[:-n]
    if inplace:
        return self.__setinplace(a, inplace)
    return a
def round(self, d=0, inplace=False)

Rounds the Array to the given number of decimals.

Expand source code
def round(self, d=0, inplace=False):
    """ Rounds the Array to the given number of decimals. """
    a = map(lambda e: round(e, d), self)
    if inplace:
        return self.__setinplace(a, inplace)
    return Array(a)
def setdifference(self, b)

Difference between this Array and another iterable. Returns the unique values in this Array that are not in sequence b. Does not preserve order of elements.

Expand source code
def setdifference(self, b):
    """
    Difference between this Array and another iterable.
    Returns the unique values in this Array that are not in sequence b.
    Does not preserve order of elements.
    """
    return Array(set(self).difference(set(b)))
def setintersect(self, b)

Intersection between this Array and another iterable. Returns the unique values that are both in this Array and sequence b. Does not preserve order of elements.

Expand source code
def setintersect(self, b):
    """
    Intersection between this Array and another iterable.
    Returns the unique values that are both in this Array and sequence b.
    Does not preserve order of elements.
    """
    return Array(set(self).intersection(set(b)))
def setunion(self, b)

Union of this Array and another iterable. Returns the unique values that are in either this Array or sequence b. Does not preserve order of elements.

Expand source code
def setunion(self, b):
    """
    Union of this Array and another iterable.
    Returns the unique values that are in either this Array or sequence b.
    Does not preserve order of elements.
    """
    return Array(set(self).union(set(b)))
def sort(self, inplace=False, **kwargs)

Sorts this Array.

Expand source code
def sort(self, inplace=False, **kwargs):
    """ Sorts this Array. """
    if inplace:
        self.__validate_bool_arg(inplace, "inplace")
        super().sort(**kwargs)
        return self
    return Array(sorted(self, **kwargs))
def sortby(self, func, reverse=False, inplace=False)

Sorts this Array according to a function defining the sorting criteria.

Expand source code
def sortby(self, func, reverse=False, inplace=False):
    """
    Sorts this Array according to a function
    defining the sorting criteria.
    """
    if inplace:
        self.__validate_bool_arg(inplace, "inplace")
        super().sort(key=func, reverse=reverse)
        return self
    return Array(sorted(self, key=func, reverse=reverse))
def split(self, c)

Splits an Array into subarrays using provided argument as the delimiter element.

Expand source code
def split(self, c):
    """
    Splits an Array into subarrays using provided argument as the delimiter element.
    """
    try:
        i = self.index(c)
        v = self[:i].unsqueeze if i != 0 else Array()
        for e in self[i + 1 :].split(c):
            if len(e) != 0:
                v.append(e)
        return v
    except ValueError:
        return self.unsqueeze
def split_at(self, n)

Splits this Array into subarrays at specified index or indices.

Expand source code
def split_at(self, n):
    """ Splits this Array into subarrays at specified index or indices. """
    if isinstance(n, int):
        return Array(self[:n], self[n:])
    n = Array(0, *n, self.size)
    return Array(self[n[i] : n[i + 1]] for i in range(n.size - 1))
def split_to(self, n)

Splits this Array to n equal length subarrays

Expand source code
def split_to(self, n):
    """ Splits this Array to n equal length subarrays """
    if self.size % n != 0:
        raise ValueError("Split does not result in an equal division")
    d = self.size // n
    return Array(self[d * i : d * (i + 1)] for i in range(n))
def starmap(self, func)

Returns an Array by applying provided function to this Array with itertools.starmap

Expand source code
def starmap(self, func):
    """
    Returns an Array by applying provided function
    to this Array with itertools.starmap
    """
    return Array(itertools.starmap(func, self))
def sub(self, e, inplace=False)

Element-wise subtraction with given scalar or sequence.

Expand source code
def sub(self, e, inplace=False):
    """
    Element-wise subtraction with given scalar or sequence.
    """
    return self.__operate(operator.sub, e, inplace)
def sum(self, start=0)

Returns the sum of the Array elements.

Expand source code
def sum(self, start=0):
    """ Returns the sum of the Array elements. """
    return sum(self, start)
def takewhile(self, func)

Takes the longest prefix of elements that satisfy the given predicate.

Expand source code
def takewhile(self, func):
    """ Takes the longest prefix of elements that satisfy the given predicate. """
    return Array(itertools.takewhile(func, self))
def to_dict(self)

Creates a dictionary from an Array of Arrays / tuples.

Expand source code
def to_dict(self):
    """ Creates a dictionary from an Array of Arrays / tuples. """
    return dict(self)
def to_iter(self)

Returns an iterator for the Array.

Expand source code
def to_iter(self):
    """ Returns an iterator for the Array."""
    for e in self:
        yield e
def to_set(self)

Returns set of the Array elements. Order is not preserved.

Expand source code
def to_set(self):
    """ Returns set of the Array elements. Order is not preserved. """
    return set(self)
def to_str(self)

Creates a string representation of the Array. See Array.join for more functionality.

Expand source code
def to_str(self):
    """
    Creates a string representation of the Array.
    See Array.join for more functionality.
    """
    return "".join(str(v) for v in self)
def to_tuple(self)

Returns a copy of the Array as an tuple.

Expand source code
def to_tuple(self):
    """ Returns a copy of the Array as an tuple. """
    return tuple(self.copy())
def union(self, b)

Union of this Array and another iterable. Returns the values that are in either this Array or sequence b.

Expand source code
def union(self, b):
    """
    Union of this Array and another iterable.
    Returns the values that are in either this Array or sequence b.
    """
    return self + b
def unique(self)

Selects unique values in this Array. Does not preserve order of elements.

Expand source code
def unique(self):
    """
    Selects unique values in this Array.
    Does not preserve order of elements.
    """
    return Array(set(self))
def unzip(self)

'Unzips' nested Arrays by unpacking its elements into a zip.

>>> Array((1, "a"), (2, "b")).unzip()
Array(Array(1, 2), Array('a', 'b'))
Expand source code
def unzip(self):
    """
    'Unzips' nested Arrays by unpacking its elements into a zip.

    >>> Array((1, "a"), (2, "b")).unzip()
    Array(Array(1, 2), Array('a', 'b'))
    """
    if not all(map(lambda e: isinstance(e, Iterable), self)):
        raise TypeError("Array elements must support iteration")
    return Array(zip(*self))
def windows(self, size, stride=1, drop_last=True)

Returns sliding windows of width size over the Array. If drop_last is True, drops the last subarrays that are shorter than the window size.

Expand source code
def windows(self, size, stride=1, drop_last=True):
    """
    Returns sliding windows of width `size` over the Array.
    If `drop_last` is True, drops the last subarrays that are
    shorter than the window size.
    """
    self.__validate_bool_arg(drop_last, "drop_last")
    end = (self.size - size + 1) if drop_last else self.size
    return Array(self[i : i + size] for i in range(0, end, stride))
def zip(self, *args)
Expand source code
def zip(self, *args):
    return Array(zip(self, *args))
def zip_all(self, *args, default=None)

Zips the sequences. If the iterables are of uneven length, missing values are filled with default value.

Expand source code
def zip_all(self, *args, default=None):
    """
    Zips the sequences. If the iterables are
    of uneven length, missing values are filled with default value.
    """
    return Array(itertools.zip_longest(self, *args, fillvalue=default))

Inherited members