def test_view_of_view(matrix_type, subset_func, subset_func2):
    adata = gen_adata((30, 15), X_type=matrix_type)
    adata.raw = adata
    if subset_func is single_subset:
        pytest.xfail("Other subset generating functions have trouble with this")
    var_s1 = subset_func(adata.var_names, min_size=4)
    var_view1 = adata[:, var_s1]
    var_s2 = subset_func2(var_view1.var_names)
    var_view2 = var_view1[:, var_s2]
    assert var_view2._adata_ref is adata
    obs_s1 = subset_func(adata.obs_names, min_size=4)
    obs_view1 = adata[obs_s1, :]
    obs_s2 = subset_func2(obs_view1.obs_names)
    assert adata[obs_s1, :][:, var_s1][obs_s2, :]._adata_ref is adata

    view_of_actual_copy = adata[:, var_s1].copy()[obs_s1, :].copy()[:, var_s2].copy()

    view_of_view_copy = adata[:, var_s1][obs_s1, :][:, var_s2].copy()

    assert_equal(view_of_actual_copy, view_of_view_copy, exact=True)
def subset_examples(example_dict, indices_to_keep, create_new_dict=False):
    """Subsets examples in dictionary.

    :param example_dict: See doc for `write_example_file`.
    :param indices_to_keep: 1-D numpy array with indices of examples to keep.
    :param create_new_dict: Boolean flag.  If True, this method will create a
        new dictionary, leaving the input dictionary untouched.
    :return: example_dict: Same as input, but possibly with fewer examples.
    """

    error_checking.assert_is_integer_numpy_array(indices_to_keep)
    error_checking.assert_is_numpy_array(indices_to_keep, num_dimensions=1)
    error_checking.assert_is_boolean(create_new_dict)

    if not create_new_dict:
        for this_key in MAIN_KEYS:
            optional_key_missing = (
                this_key not in REQUIRED_MAIN_KEYS
                and this_key not in example_dict
            )

            if optional_key_missing:
                continue

            if this_key == TARGET_MATRIX_KEY:
                if this_key in example_dict:
                    example_dict[this_key] = (
                        example_dict[this_key][indices_to_keep, ...]
                    )
                else:
                    example_dict[TARGET_VALUES_KEY] = (
                        example_dict[TARGET_VALUES_KEY][indices_to_keep]
                    )

                continue

            if this_key == FULL_IDS_KEY:
                example_dict[this_key] = [
                    example_dict[this_key][k] for k in indices_to_keep
                ]
            else:
                example_dict[this_key] = example_dict[this_key][
                    indices_to_keep, ...]

        return example_dict

    new_example_dict = {}

    for this_key in METADATA_KEYS:
        sounding_key_missing = (
            this_key in [SOUNDING_FIELDS_KEY, SOUNDING_HEIGHTS_KEY]
            and this_key not in example_dict
        )

        if sounding_key_missing:
            continue

        if this_key == TARGET_NAMES_KEY:
            if this_key in example_dict:
                new_example_dict[this_key] = example_dict[this_key]
            else:
                new_example_dict[TARGET_NAME_KEY] = example_dict[
                    TARGET_NAME_KEY]

            continue

        new_example_dict[this_key] = example_dict[this_key]

    for this_key in MAIN_KEYS:
        optional_key_missing = (
            this_key not in REQUIRED_MAIN_KEYS
            and this_key not in example_dict
        )

        if optional_key_missing:
            continue

        if this_key == TARGET_MATRIX_KEY:
            if this_key in example_dict:
                new_example_dict[this_key] = (
                    example_dict[this_key][indices_to_keep, ...]
                )
            else:
                new_example_dict[TARGET_VALUES_KEY] = (
                    example_dict[TARGET_VALUES_KEY][indices_to_keep]
                )

            continue

        if this_key == FULL_IDS_KEY:
            new_example_dict[this_key] = [
                example_dict[this_key][k] for k in indices_to_keep
            ]
        else:
            new_example_dict[this_key] = example_dict[this_key][
                indices_to_keep, ...]

    return new_example_dict