Generalization of group_item. Convert a flast list of ids into a heirarchical dictionary.

    TODO: move to util_dict

    Reference:
        http://stackoverflow.com/questions/10193235/python-translate-a-table-to-a-hierarchical-dictionary

    Args:
        item_list (list):
        groupids_list (list):

    CommandLine:
        python -m utool.util_dict --exec-hierarchical_group_items

    Example:
        >>> # ENABLE_DOCTEST
        >>> from utool.util_dict import *  # NOQA
        >>> import utool as ut
        >>> item_list     = [1, 2, 3, 4]
        >>> groupids_list = [[1, 1, 2, 2]]
        >>> tree = hierarchical_group_items(item_list, groupids_list)
        >>> result = ('tree = ' + ut.repr4(tree, nl=len(groupids_list) - 1))
        >>> print(result)
        tree = {1: [1, 2], 2: [3, 4]}

    Example:
        >>> # ENABLE_DOCTEST
        >>> from utool.util_dict import *  # NOQA
        >>> import utool as ut
        >>> item_list     = [1, 2, 3, 4, 5, 6, 7, 8]
        >>> groupids_list = [[1, 2, 1, 2, 1, 2, 1, 2], [3, 2, 2, 2, 3, 1, 1, 1]]
        >>> tree = hierarchical_group_items(item_list, groupids_list)
        >>> result = ('tree = ' + ut.repr4(tree, nl=len(groupids_list) - 1))
        >>> print(result)
        tree = {
            1: {1: [7], 2: [3], 3: [1, 5]},
            2: {1: [6, 8], 2: [2, 4]},
        }

    Example:
        >>> # ENABLE_DOCTEST
        >>> from utool.util_dict import *  # NOQA
        >>> import utool as ut
        >>> item_list     = [1, 2, 3, 4]
        >>> groupids_list = [[1, 1, 1, 2], [1, 2, 2, 2], [1, 3, 1, 1]]
        >>> tree = hierarchical_group_items(item_list, groupids_list)
        >>> result = ('tree = ' + ut.repr4(tree, nl=len(groupids_list) - 1))
        >>> print(result)
        tree = {
            1: {
                1: {1: [1]},
                2: {1: [3], 3: [2]},
            },
            2: {
                2: {1: [4]},
            },
        }

def hierarchical_group_items(item_list, groupids_list):
    """
    Generalization of group_item. Convert a flast list of ids into a heirarchical dictionary.

    TODO: move to util_dict

    Reference:
        http://stackoverflow.com/questions/10193235/python-translate-a-table-to-a-hierarchical-dictionary

    Args:
        item_list (list):
        groupids_list (list):

    CommandLine:
        python -m utool.util_dict --exec-hierarchical_group_items

    Example:
        >>> # ENABLE_DOCTEST
        >>> from utool.util_dict import *  # NOQA
        >>> import utool as ut
        >>> item_list     = [1, 2, 3, 4]
        >>> groupids_list = [[1, 1, 2, 2]]
        >>> tree = hierarchical_group_items(item_list, groupids_list)
        >>> result = ('tree = ' + ut.repr4(tree, nl=len(groupids_list) - 1))
        >>> print(result)
        tree = {1: [1, 2], 2: [3, 4]}

    Example:
        >>> # ENABLE_DOCTEST
        >>> from utool.util_dict import *  # NOQA
        >>> import utool as ut
        >>> item_list     = [1, 2, 3, 4, 5, 6, 7, 8]
        >>> groupids_list = [[1, 2, 1, 2, 1, 2, 1, 2], [3, 2, 2, 2, 3, 1, 1, 1]]
        >>> tree = hierarchical_group_items(item_list, groupids_list)
        >>> result = ('tree = ' + ut.repr4(tree, nl=len(groupids_list) - 1))
        >>> print(result)
        tree = {
            1: {1: [7], 2: [3], 3: [1, 5]},
            2: {1: [6, 8], 2: [2, 4]},
        }

    Example:
        >>> # ENABLE_DOCTEST
        >>> from utool.util_dict import *  # NOQA
        >>> import utool as ut
        >>> item_list     = [1, 2, 3, 4]
        >>> groupids_list = [[1, 1, 1, 2], [1, 2, 2, 2], [1, 3, 1, 1]]
        >>> tree = hierarchical_group_items(item_list, groupids_list)
        >>> result = ('tree = ' + ut.repr4(tree, nl=len(groupids_list) - 1))
        >>> print(result)
        tree = {
            1: {
                1: {1: [1]},
                2: {1: [3], 3: [2]},
            },
            2: {
                2: {1: [4]},
            },
        }

    """
    # Construct a defaultdict type with the appropriate number of levels
    num_groups = len(groupids_list)
    leaf_type = partial(defaultdict, list)
    if num_groups > 1:
        node_type = leaf_type
        for _ in range(len(groupids_list) - 2):
            node_type = partial(defaultdict, node_type)
        root_type = node_type
    elif num_groups == 1:
        root_type = list
    else:
        raise ValueError('must suply groupids')
    tree = defaultdict(root_type)
    #
    groupid_tuple_list = list(zip(*groupids_list))
    for groupid_tuple, item in zip(groupid_tuple_list, item_list):
        node = tree
        for groupid in groupid_tuple:
            node = node[groupid]
        node.append(item)
    return tree