from org.meteoinfo.ndarray.math import ArrayUtil from .. import core as np __all__ = ['unique', 'intersect1d'] def _unique1d(ar, return_index=False, return_inverse=False, return_counts=False): """ Find the unique elements of an array, ignoring shape. """ ar = np.asanyarray(ar).flatten() optional_indices = return_index or return_inverse if optional_indices: perm = ar.argsort() aux = ar[perm] else: ar.sort() aux = ar mask = np.empty(aux.shape, dtype=np.bool_) mask[:1] = True if aux.shape[0] > 0 and aux.dtype.kind in "cfmM" and np.isnan(aux[-1]): if aux.dtype.kind == "c": # for complex all NaNs are considered equivalent aux_firstnan = np.searchsorted(np.isnan(aux), True, side='left') else: aux_firstnan = np.searchsorted(aux, aux[-1], side='left') if aux_firstnan > 0: mask[1:aux_firstnan] = ( aux[1:aux_firstnan] != aux[:aux_firstnan - 1]) mask[aux_firstnan] = True mask[aux_firstnan + 1:] = False else: mask[1:] = aux[1:] != aux[:-1] ret = (aux[mask],) if return_index: ret += (perm[mask],) if return_inverse: imask = np.cumsum(mask) - 1 inv_idx = np.empty(mask.shape, dtype=np.intp) inv_idx[perm] = imask ret += (inv_idx,) if return_counts: idx = np.concatenate(np.nonzero(mask) + ([mask.size],)) ret += (np.diff(idx),) return ret def unique(a, return_index=False, axis=None): """ Find the unique elements of an array. Returns the sorted unique elements of an array. :param a: (*array_like*) Array to be sorted. :param return_index: (*bool*) Optional, If True, also return the indices of ar (along the specified axis, if provided, or in the flattened array) that result in the unique array. :param axis: (*int or None*) Optional. Axis along which to operate on. If None, the array is flattened. :returns: (*NDArray*) Sorted unique elements of input array. """ if isinstance(a, list): a = np.array(a) if return_index: r = ArrayUtil.uniqueIndex(a.asarray(), axis) return np.NDArray(r[0]), np.NDArray(r[1]) else: r = ArrayUtil.unique(a.asarray(), axis) return np.NDArray(r) def intersect1d(ar1, ar2, assume_unique=False, return_indices=False): """ Find the intersection of two arrays. Return the sorted, unique values that are in both of the input arrays. Parameters ---------- ar1, ar2 : array_like Input arrays. Will be flattened if not already 1D. assume_unique : bool If True, the input arrays are both assumed to be unique, which can speed up the calculation. If True but ``ar1`` or ``ar2`` are not unique, incorrect results and out-of-bounds indices could result. Default is False. return_indices : bool If True, the indices which correspond to the intersection of the two arrays are returned. The first instance of a value is used if there are multiple. Default is False. Returns ------- intersect1d : ndarray Sorted 1D array of common and unique elements. comm1 : ndarray The indices of the first occurrences of the common values in `ar1`. Only provided if `return_indices` is True. comm2 : ndarray The indices of the first occurrences of the common values in `ar2`. Only provided if `return_indices` is True. See Also -------- numeric.lib.arraysetops : Module with a number of other functions for performing set operations on arrays. Examples -------- >>> np.intersect1d([1, 3, 4, 3], [3, 1, 2, 1]) array([1, 3]) To intersect more than two arrays, use functools.reduce: >>> from functools import reduce >>> reduce(np.intersect1d, ([1, 3, 4, 3], [3, 1, 2, 1], [6, 3, 4, 2])) array([3]) To return the indices of the values common to the input arrays along with the intersected values: >>> x = np.array([1, 1, 2, 3, 4]) >>> y = np.array([2, 1, 4, 6]) >>> xy, x_ind, y_ind = np.intersect1d(x, y, return_indices=True) >>> x_ind, y_ind (array([0, 2, 4]), array([1, 0, 2])) >>> xy, x[x_ind], y[y_ind] (array([1, 2, 4]), array([1, 2, 4]), array([1, 2, 4])) """ ar1 = np.asanyarray(ar1) ar2 = np.asanyarray(ar2) if not assume_unique: if return_indices: ar1, ind1 = unique(ar1, return_index=True) ar2, ind2 = unique(ar2, return_index=True) else: ar1 = unique(ar1) ar2 = unique(ar2) else: ar1 = ar1.ravel() ar2 = ar2.ravel() aux = np.concatenate((ar1, ar2)) if return_indices: aux_sort_indices = np.argsort(aux) aux = aux[aux_sort_indices] else: aux.sort() mask = aux[1:] == aux[:-1] int1d = aux[:-1][mask] if return_indices: ar1_indices = aux_sort_indices[:-1][mask] ar2_indices = aux_sort_indices[1:][mask] - ar1.size if not assume_unique: ar1_indices = ind1[ar1_indices] ar2_indices = ind2[ar2_indices] return int1d, ar1_indices, ar2_indices else: return int1d