def subset(train, idx, keep_other=True):
    """Subset the `train=(x, y)` data tuple, each of the form:

    - list, np.ndarray
    - tuple, np.ndarray
    - dictionary, np.ndarray
    - np.ndarray, np.ndarray

    # Note
        In case there are other data present in the tuple:
        `(x, y, other1, other2, ...)`, these get passed on as:
        `(x_sub, y_sub, other1, other2)`

    # Arguments
        train: `(x,y, other1, other2, ...)` tuple of data
        idx: indices to subset the data with
        keep_other: bool; If True, the additional tuple elements `(other1, other2, ...)` are passed
    together with `(x, y)` but don't get subsetted.
    """
    test_len(train)
    y = train[1][idx]
    # x split
    if isinstance(train[0], (list, tuple)):
        x = [x[idx] for x in train[0]]
    elif isinstance(train[0], dict):
        x = {k: v[idx] for k, v in train[0].items()}
    elif isinstance(train[0], np.ndarray):
        x = train[0][idx]
    else:
        raise ValueError("Input can only be of type: list, dict or np.ndarray")

    if keep_other:
        return (x, y) + train[2:]
    else:
        return (x, y)