def _traverse_supported_dataset_with_intermediate(
    dataset: TraverseT,
    values_selector: Callable[
        [TraverseT, Optional[List[int]], Optional[T]], Optional[List[Y]]
    ],
    intermediate_selector: Optional[Callable[[TraverseT, Optional[T]], T]] = None,
    intermediate: Optional[T] = None,
    indices: Optional[List[int]] = None,
) -> List[Y]:
    """
    Traverse the given dataset by gathering required info.

    The given dataset is traversed by covering all sub-datasets
    contained in PyTorch :class:`Subset` and :class`ConcatDataset`
    as well as :class:`AvalancheDataset`.

    For each dataset, the `values_selector` will be called to gather
    the required information. The values returned by the given selector
    are then concatenated to create a final list of values.

    While traversing, the `intermediate_selector` (if provided)
    will be called to create a chain of intermediate values, which
    are passed to `values_selector`.

    :param dataset: The dataset to traverse.
    :param values_selector: A function that, given the dataset
        and the indices to consider (which may be None if the entire
        dataset must be considered), returns a list of selected values.
    :returns: The list of selected values.
    """

    if intermediate_selector is not None:
        intermediate = intermediate_selector(dataset, intermediate)

    leaf_result: Optional[List[Y]] = values_selector(dataset, indices, intermediate)

    if leaf_result is not None:
        if len(leaf_result) == 0:
            raise RuntimeError("Empty result")
        return leaf_result

    if isinstance(dataset, AvalancheDataset):
        return list(
            _traverse_supported_dataset_with_intermediate(
                dataset._flat_data,
                values_selector,
                intermediate_selector=intermediate_selector,
                indices=indices,
                intermediate=intermediate,
            )
        )

    if isinstance(dataset, Subset):
        if indices is None:
            indices = [dataset.indices[x] for x in range(len(dataset))]
        else:
            indices = [dataset.indices[x] for x in indices]

        return list(
            _traverse_supported_dataset_with_intermediate(
                dataset.dataset,
                values_selector,
                intermediate_selector=intermediate_selector,
                indices=indices,
                intermediate=intermediate,
            )
        )

    if isinstance(dataset, FlatData) and dataset._indices is not None:
        if indices is None:
            indices = [dataset._indices[x] for x in range(len(dataset))]
        else:
            indices = [dataset._indices[x] for x in indices]

    if isinstance(dataset, (ConcatDataset, FlatData)):
        result: List[Y] = []

        concatenated_datasets: Sequence[TraverseT]
        if isinstance(dataset, ConcatDataset):
            concatenated_datasets = dataset.datasets
        else:
            concatenated_datasets = dataset._datasets

        if indices is None:
            for c_dataset in concatenated_datasets:
                result += list(
                    _traverse_supported_dataset_with_intermediate(
                        c_dataset,
                        values_selector,
                        intermediate_selector=intermediate_selector,
                        indices=indices,
                        intermediate=intermediate,
                    )
                )
            if len(result) == 0:
                raise RuntimeError("Empty result")
            return result

        datasets_to_indexes = defaultdict(list)
        indexes_to_dataset = []
        datasets_len = []
        recursion_result = []

        all_size = 0
        for c_dataset in concatenated_datasets:
            len_dataset = len(c_dataset)
            datasets_len.append(len_dataset)
            all_size += len_dataset

        for subset_idx in indices:
            dataset_idx, pattern_idx = find_list_from_index(
                subset_idx, datasets_len, all_size
            )
            datasets_to_indexes[dataset_idx].append(pattern_idx)
            indexes_to_dataset.append(dataset_idx)

        for dataset_idx, c_dataset in enumerate(concatenated_datasets):
            recursion_result.append(
                deque(
                    _traverse_supported_dataset_with_intermediate(
                        c_dataset,
                        values_selector,
                        intermediate_selector=intermediate_selector,
                        indices=datasets_to_indexes[dataset_idx],
                        intermediate=intermediate,
                    )
                )
            )

        result = []
        for idx in range(len(indices)):
            dataset_idx = indexes_to_dataset[idx]
            result.append(recursion_result[dataset_idx].popleft())

        if len(result) == 0:
            raise RuntimeError("Empty result")
        return result

    raise ValueError("Error: can't find the needed data in the given dataset")

    Traverse the given dataset by gathering required info.

    The given dataset is traversed by covering all sub-datasets
    contained in PyTorch :class:`Subset` and :class`ConcatDataset`
    as well as :class:`AvalancheDataset`.

    For each dataset, the `values_selector` will be called to gather
    the required information. The values returned by the given selector
    are then concatenated to create a final list of values.

    While traversing, the `intermediate_selector` (if provided)
    will be called to create a chain of intermediate values, which
    are passed to `values_selector`.

    :param dataset: The dataset to traverse.
    :param values_selector: A function that, given the dataset
        and the indices to consider (which may be None if the entire
        dataset must be considered), returns a list of selected values.
    :returns: The list of selected values.
    
avalanche/benchmarks/utils/dataset_traversal_utils.py