# AUTOGENERATED! DO NOT EDIT! File to edit: ../nbs/10_misc.ipynb.

# %% auto 0
__all__ = ['pair', 'steps', 'calcgrid', 'grididx', 'pad4grid', 'takekeys']

# %% ../nbs/10_misc.ipynb 6
import math
from functools import wraps

# %% ../nbs/10_misc.ipynb 8
from typing import Iterable, overload

# %% ../nbs/10_misc.ipynb 11
#| export

# %% ../nbs/10_misc.ipynb 13
#| export


# %% ../nbs/10_misc.ipynb 15
#| export


# %% ../nbs/10_misc.ipynb 17
#| export


# %% ../nbs/10_misc.ipynb 19
from atup import fillnone
from chck import isdict
from quac import nums, rect, xypos

# %% ../nbs/10_misc.ipynb 21
from .cons import WRAPS_ASSIGN_ANNDOCS

# %% ../nbs/10_misc.ipynb 23
def pair(a: nums, n: int = 2, i: int = 1) -> tuple[nums, ...]:
    '''Pair numbers in an array
    
    Parameters
    ----------
    a: ints
        array iterable of numbers to pair
        
    n: int
        The number to of elements pair in each tuple
        
    i: int
        The number to increment between elements in `a`
        
    Returns
    -------
    tuple[ints, ...]
        tuple of paired numbers each containing `n` paired elements from `a`.
        
    Examples
    --------
    >>> pair(np.arange(1, 6), 2)
    [(1, 2), (2, 3), (3, 4), (4, 5)]
    
    >>> pair(np.arange(1, 6), 3)
    [(1, 2, 3), (2, 3, 4), (3, 4, 5)]
    
    >>> pair(np.arange(1, 6), 2, 2)
    [(1, 3), (2, 4), (3, 5)]
    
    See Also
    --------
    steps: Alias for `pair`.
    '''
    if not isinstance(a, Iterable): a = [a]
    return tuple(zip(a, *(a[(i * _):] for _ in range(1, n))))

@wraps(pair, assigned=WRAPS_ASSIGN_ANNDOCS)
def steps(*args, **kwargs):
    '''Alias for `pair`.'''
    return pair(*args, **kwargs)

# %% ../nbs/10_misc.ipynb 26
def calcgrid(n: int) -> rect:
    '''
    Find the closest rectangle layout that accommodates n elements.

    Parameters
    ----------
    n : int
        The number of elements to accommodate in the grid.

    Returns
    -------
    Grid
        A tuple representing the dimensions (rows, cols) of the grid.
    '''
    x = math.isqrt(n)
    while n % x != 0: x -= 1
    y = n // x
    return x, y

# %% ../nbs/10_misc.ipynb 28
def grididx(pos: xypos, grid: rect) -> int:
    '''
    Calculate the linear index of an element in a `grid` given its `(row, col)` position (`pos`).

    Parameters
    ----------
    pos : XYPos
        A tuple representing the row and column position of the element in the grid.
    grid : Grid
        A tuple representing the dimensions of the grid (rows, columns).

    Returns
    -------
    int
        The linear index of the element in the grid.
    '''
    nrows, ncols = grid
    cur_r, cur_c = pos
    return cur_r * ncols + cur_c

# %% ../nbs/10_misc.ipynb 30
@overload
def pad4grid(arr: list, rows: int, cols: int) -> list: ...
@overload
def pad4grid(arr: list, n: int) -> list: ...
def pad4grid(arr: list, *args) -> list:
    '''
    Pad the list of objects to the closest grid layout that accommodates a specified number of elements.

    Parameters
    ----------
    arr : list
        The list to be padded.
    args : int
        The dimensions of the grid `(rows, cols)` or the total number of elements `n`.

    Returns
    -------
    list
        The padded list.
    '''
    rows, cols = args[0], (1 if len(args) <= 1 else args[1])
    return list(fillnone(arr, rows * cols))

# %% ../nbs/10_misc.ipynb 32
def takekeys(d: dict, keys: list | dict) -> dict:
    keys = keys or []
    if isdict(keys): keys = keys.keys()
    return {k: d.get(k, None) for k in keys if k in d}

# %% ../nbs/10_misc.ipynb 34
#| export
