def find_duplicates(items, k=<NUM_LIT:2>, key=None):
<EOL>duplicates = defaultdict(list)<EOL>if key is None:<EOL><INDENT>for count, item in enumerate(items):<EOL><INDENT>duplicates[item].append(count)<EOL><DEDENT><DEDENT>else:<EOL><INDENT>for count, item in enumerate(items):<EOL><INDENT>duplicates[key(item)].append(count)<EOL><DEDENT><DEDENT>for key in list(duplicates.keys()):<EOL><INDENT>if len(duplicates[key]) < k:<EOL><INDENT>del duplicates[key]<EOL><DEDENT><DEDENT>duplicates = dict(duplicates)<EOL>return duplicates<EOL>
Find all duplicate items in a list.

Search for all items that appear more than `k` times and return a mapping
from each (k)-duplicate item to the positions it appeared in.

Args:
    items (Iterable): hashable items possibly containing duplicates
    k (int): only return items that appear at least `k` times (default=2)
    key (Callable, optional): Returns indices where `key(items[i])`
        maps to a particular value at least k times.

Returns:
    dict: maps each duplicate item to the indices at which it appears

CommandLine:
    python -m ubelt.util_dict find_duplicates

Example:
    >>> import ubelt as ub
    >>> items = [0, 0, 1, 2, 3, 3, 0, 12, 2, 9]
    >>> duplicates = ub.find_duplicates(items)
    >>> print('items = %r' % (items,))
    >>> print('duplicates = %r' % (duplicates,))
    >>> assert duplicates == {0: [0, 1, 6], 2: [3, 8], 3: [4, 5]}
    >>> assert ub.find_duplicates(items, 3) == {0: [0, 1, 6]}

Example:
    >>> import ubelt as ub
    >>> items = [0, 0, 1, 2, 3, 3, 0, 12, 2, 9]
    >>> # note: k can be 0
    >>> duplicates = ub.find_duplicates(items, k=0)
    >>> print(ub.repr2(duplicates, nl=0))
    {0: [0, 1, 6], 1: [2], 2: [3, 8], 3: [4, 5], 9: [9], 12: [7]}

Example:
    >>> import ubelt as ub
    >>> items = [10, 11, 12, 13, 14, 15, 16]
    >>> duplicates = ub.find_duplicates(items, key=lambda x: x // 2)
    >>> print(ub.repr2(duplicates, nl=0))
    {5: [0, 1], 6: [2, 3], 7: [4, 5]}