def set_xindex(
        self,
        coord_names: str | Sequence[Hashable],
        index_cls: type[Index] | None = None,
        **options,
    ) -> Self:
        """Set a new, Xarray-compatible index from one or more existing
        coordinate(s).

        Parameters
        ----------
        coord_names : str or list
            Name(s) of the coordinate(s) used to build the index.
            If several names are given, their order matters.
        index_cls : subclass of :class:`~xarray.indexes.Index`, optional
            The type of index to create. By default, try setting
            a ``PandasIndex`` if ``len(coord_names) == 1``,
            otherwise a ``PandasMultiIndex``.
        **options
            Options passed to the index constructor.

        Returns
        -------
        obj : Dataset
            Another dataset, with this dataset's data and with a new index.

        """
        # the Sequence check is required for mypy
        if is_scalar(coord_names) or not isinstance(coord_names, Sequence):
            coord_names = [coord_names]

        if index_cls is None:
            if len(coord_names) == 1:
                index_cls = PandasIndex
            else:
                index_cls = PandasMultiIndex
        elif not issubclass(index_cls, Index):
            raise TypeError(f"{index_cls} is not a subclass of xarray.Index")

        invalid_coords = set(coord_names) - self._coord_names

        if invalid_coords:
            msg = ["invalid coordinate(s)"]
            no_vars = invalid_coords - set(self._variables)
            data_vars = invalid_coords - no_vars
            if no_vars:
                msg.append(f"those variables don't exist: {no_vars}")
            if data_vars:
                msg.append(
                    f"those variables are data variables: {data_vars}, use `set_coords` first"
                )
            raise ValueError("\n".join(msg))

        # we could be more clever here (e.g., drop-in index replacement if index
        # coordinates do not conflict), but let's not allow this for now
        indexed_coords = set(coord_names) & set(self._indexes)

        if indexed_coords:
            raise ValueError(
                f"those coordinates already have an index: {indexed_coords}"
            )

        coord_vars = {name: self._variables[name] for name in coord_names}

        index = index_cls.from_variables(coord_vars, options=options)

        new_coord_vars = index.create_variables(coord_vars)

        # special case for setting a pandas multi-index from level coordinates
        # TODO: remove it once we depreciate pandas multi-index dimension (tuple
        # elements) coordinate
        if isinstance(index, PandasMultiIndex):
            coord_names = [index.dim] + list(coord_names)

        variables: dict[Hashable, Variable]
        indexes: dict[Hashable, Index]

        if len(coord_names) == 1:
            variables = self._variables.copy()
            indexes = self._indexes.copy()

            name = list(coord_names).pop()
            if name in new_coord_vars:
                variables[name] = new_coord_vars[name]
            indexes[name] = index
        else:
            # reorder variables and indexes so that coordinates having the same
            # index are next to each other
            variables = {}
            for name, var in self._variables.items():
                if name not in coord_names:
                    variables[name] = var

            indexes = {}
            for name, idx in self._indexes.items():
                if name not in coord_names:
                    indexes[name] = idx

            for name in coord_names:
                try:
                    variables[name] = new_coord_vars[name]
                except KeyError:
                    variables[name] = self._variables[name]
                indexes[name] = index

        return self._replace(
            variables=variables,
            coord_names=self._coord_names | set(coord_names),
            indexes=indexes,
        )
Set a new, Xarray-compatible index from one or more existing
        coordinate(s).

        Parameters
        ----------
        coord_names : str or list
            Name(s) of the coordinate(s) used to build the index.
            If several names are given, their order matters.
        index_cls : subclass of :class:`~xarray.indexes.Index`, optional
            The type of index to create. By default, try setting
            a ``PandasIndex`` if ``len(coord_names) == 1``,
            otherwise a ``PandasMultiIndex``.
        **options
            Options passed to the index constructor.

        Returns
        -------
        obj : Dataset
            Another dataset, with this dataset's data and with a new index.

        
xarray/core/dataset.py