# Path: ubelt/util_const.py
# class _NoParamType(object):
#     def __new__(cls):
#     def __reduce__(self):
#     def __copy__(self):
#     def __deepcopy__(self, memo):
#     def __str__(cls):
#     def __repr__(cls):
#     def __bool__(self):
# 
# Path: ubelt/util_list.py
# class chunks(object):
#     def __init__(self, items, chunksize=None, nchunks=None, total=None,
#                  bordermode='none', legacy=False):
#     def __len__(self):
#     def __iter__(self):
#     def _new_iterator(self):
#             def replicator(items):
#     def noborder(items, chunksize):
#     def cycle(items, chunksize):
#     def replicate(items, chunksize):
# def iterable(obj, strok=False):
# def take(items, indices, default=util_const.NoParam):
# def compress(items, flags):
# def flatten(nested):
# def unique(items, key=None):
# def argunique(items, key=None):
# def unique_flags(items, key=None):
# def boolmask(indices, maxval=None):
# def iter_window(iterable, size=2, step=1, wrap=False):
# def allsame(iterable, eq=operator.eq):
# def argsort(indexable, key=None, reverse=False):
# def argmax(indexable, key=None):
# def argmin(indexable, key=None):
# def peek(iterable, default=util_const.NoParam):
# 
# Path: ubelt/util_const.py
# class _NoParamType(object):
#     def __new__(cls):
#     def __reduce__(self):
#     def __copy__(self):
#     def __deepcopy__(self, memo):
#     def __str__(cls):
#     def __repr__(cls):
#     def __bool__(self):


import operator as op
import itertools as it
from collections import OrderedDict
from collections import defaultdict
from ubelt import util_const
from ubelt import util_list
from ubelt.util_const import NoParam

def dict_subset(dict_, keys, default=util_const.NoParam, cls=OrderedDict):
    """
    Get a subset of a dictionary

    Args:
        dict_ (Dict[KT, VT]): superset dictionary

        keys (Iterable[KT]): keys to take from ``dict_``

        default (Optional[object] | util_const._NoParamType):
            if specified uses default if keys are missing.

        cls (Type[Dict], default=OrderedDict): type of the returned dictionary.

    Returns:
        Dict[KT, VT]: subset dictionary

    SeeAlso:
        :func:`dict_isect` - similar functionality, but ignores missing keys

    Example:
        >>> import ubelt as ub
        >>> dict_ = {'K': 3, 'dcvs_clip_max': 0.2, 'p': 0.1}
        >>> keys = ['K', 'dcvs_clip_max']
        >>> subdict_ = ub.dict_subset(dict_, keys)
        >>> print(ub.repr2(subdict_, nl=0))
        {'K': 3, 'dcvs_clip_max': 0.2}
    """
    keys = list(keys)

# Path: ubelt/util_const.py
# class _NoParamType(object):
#     def __new__(cls):
#     def __reduce__(self):
#     def __copy__(self):
#     def __deepcopy__(self, memo):
#     def __str__(cls):
#     def __repr__(cls):
#     def __bool__(self):
# 
# Path: ubelt/util_list.py
# class chunks(object):
#     def __init__(self, items, chunksize=None, nchunks=None, total=None,
#                  bordermode='none', legacy=False):
#     def __len__(self):
#     def __iter__(self):
#     def _new_iterator(self):
#             def replicator(items):
#     def noborder(items, chunksize):
#     def cycle(items, chunksize):
#     def replicate(items, chunksize):
# def iterable(obj, strok=False):
# def take(items, indices, default=util_const.NoParam):
# def compress(items, flags):
# def flatten(nested):
# def unique(items, key=None):
# def argunique(items, key=None):
# def unique_flags(items, key=None):
# def boolmask(indices, maxval=None):
# def iter_window(iterable, size=2, step=1, wrap=False):
# def allsame(iterable, eq=operator.eq):
# def argsort(indexable, key=None, reverse=False):
# def argmax(indexable, key=None):
# def argmin(indexable, key=None):
# def peek(iterable, default=util_const.NoParam):
# 
# Path: ubelt/util_const.py
# class _NoParamType(object):
#     def __new__(cls):
#     def __reduce__(self):
#     def __copy__(self):
#     def __deepcopy__(self, memo):
#     def __str__(cls):
#     def __repr__(cls):
#     def __bool__(self):


# Path: ubelt/util_dict.py
import operator as op
import itertools as it
from collections import OrderedDict
from collections import defaultdict
from ubelt import util_const
from ubelt import util_list
from ubelt.util_const import NoParam


def dict_subset(dict_, keys, default=util_const.NoParam, cls=OrderedDict):
    """
    Get a subset of a dictionary

    Args:
        dict_ (Dict[KT, VT]): superset dictionary

        keys (Iterable[KT]): keys to take from ``dict_``

        default (Optional[object] | util_const._NoParamType):
            if specified uses default if keys are missing.

        cls (Type[Dict], default=OrderedDict): type of the returned dictionary.

    Returns:
        Dict[KT, VT]: subset dictionary

    SeeAlso:
        :func:`dict_isect` - similar functionality, but ignores missing keys

    Example:
        >>> import ubelt as ub
        >>> dict_ = {'K': 3, 'dcvs_clip_max': 0.2, 'p': 0.1}
        >>> keys = ['K', 'dcvs_clip_max']
        >>> subdict_ = ub.dict_subset(dict_, keys)
        >>> print(ub.repr2(subdict_, nl=0))
        {'K': 3, 'dcvs_clip_max': 0.2}
    """
    keys = list(keys)

    items = util_list.take(dict_, keys, default)