Repository: pandas-dev/pandas

Issue:
BUG: Index.sort_values with key
`Index.sort_values` does 

```
idx = ensure_key_mapped(self, key)
_as = nargsort(
    items=idx, ascending=ascending, na_position=na_position, key=key
)
```

But when key is not None, nargsort does the ensure_key_mapped call again.  And ensure_key_mapped is not idempotent.

If I remove the `key=key` from the nargsort call here, the only test that fails is `TestRangeIndex::test_sort_values_key`

```
sort_order = {8: 2, 6: 0, 4: 8, 2: 10, 0: 12}
values = RangeIndex(0, 10, 2)
result = values.sort_values(key=lambda x: x.map(sort_order))
expected = Index([4, 8, 6, 0, 2], dtype="int64")
tm.assert_index_equal(result, expected, check_exact=True)
```

but it isn't obvious to me `expected` here is correct.  If we do `pd.Series(values).sort_values(key=lambda x: x.map(sort_order))` we get a different ordering.




Discussion:
expect here is indeed wrong; it's what you get when you apply the map twice allowing for nans when there are missing keys, with the nans placed at the end.
theres one other place in frame.py where we call nargsort with a key, good chance the same problem happens there too
is this issue still open?
@rhshadrach can you confirm that expected should be `Index([6, 8, 4, 2, 0])`?

Patch:
diff --git a/doc/source/whatsnew/v2.1.0.rst b/doc/source/whatsnew/v2.1.0.rst
index 84cc47e2823c5..ed8646bafc4db 100644
--- a/doc/source/whatsnew/v2.1.0.rst
+++ b/doc/source/whatsnew/v2.1.0.rst
@@ -633,11 +633,13 @@ Other
 - Bug in :meth:`DataFrame.reindex` with a ``fill_value`` that should be inferred with a :class:`ExtensionDtype` incorrectly inferring ``object`` dtype (:issue:`52586`)
 - Bug in :meth:`DataFrame.shift` and :meth:`Series.shift` and :meth:`DataFrameGroupBy.shift` when passing both "freq" and "fill_value" silently ignoring "fill_value" instead of raising ``ValueError`` (:issue:`53832`)
 - Bug in :meth:`DataFrame.shift` with ``axis=1`` on a :class:`DataFrame` with a single :class:`ExtensionDtype` column giving incorrect results (:issue:`53832`)
+- Bug in :meth:`Index.sort_values` when a ``key`` is passed (:issue:`52764`)
 - Bug in :meth:`Series.align`, :meth:`DataFrame.align`, :meth:`Series.reindex`, :meth:`DataFrame.reindex`, :meth:`Series.interpolate`, :meth:`DataFrame.interpolate`, incorrectly failing to raise with method="asfreq" (:issue:`53620`)
 - Bug in :meth:`Series.map` when giving a callable to an empty series, the returned series had ``object`` dtype. It now keeps the original dtype (:issue:`52384`)
 - Bug in :meth:`Series.memory_usage` when ``deep=True`` throw an error with Series of objects and the returned value is incorrect, as it does not take into account GC corrections (:issue:`51858`)
 - Bug in :meth:`period_range` the default behavior when freq was not passed as an argument was incorrect(:issue:`53687`)
 - Fixed incorrect ``__name__`` attribute of ``pandas._libs.json`` (:issue:`52898`)
+-
 
 .. ***DO NOT USE THIS SECTION***
 
diff --git a/pandas/core/indexes/base.py b/pandas/core/indexes/base.py
index 83eab58e3844a..7213c6093abbf 100644
--- a/pandas/core/indexes/base.py
+++ b/pandas/core/indexes/base.py
@@ -5820,15 +5820,14 @@ def sort_values(
         >>> idx.sort_values(ascending=False, return_indexer=True)
         (Index([1000, 100, 10, 1], dtype='int64'), array([3, 1, 0, 2]))
         """
-        idx = cast(Index, ensure_key_mapped(self, key))
-
         # GH 35584. Sort missing values according to na_position kwarg
         # ignore na_position for MultiIndex
         if not isinstance(self, ABCMultiIndex):
             _as = nargsort(
-                items=idx, ascending=ascending, na_position=na_position, key=key
+                items=self, ascending=ascending, na_position=na_position, key=key
             )
         else:
+            idx = cast(Index, ensure_key_mapped(self, key))
             _as = idx.argsort(na_position=na_position)
             if not ascending:
                 _as = _as[::-1]


Test patch:
diff --git a/pandas/tests/indexes/ranges/test_range.py b/pandas/tests/indexes/ranges/test_range.py
index 1ec78cf494a0c..5f137df281fa3 100644
--- a/pandas/tests/indexes/ranges/test_range.py
+++ b/pandas/tests/indexes/ranges/test_range.py
@@ -590,13 +590,18 @@ def test_isin_range(self, base):
         tm.assert_numpy_array_equal(result, expected)
 
     def test_sort_values_key(self):
-        # GH#43666
+        # GH#43666, GH#52764
         sort_order = {8: 2, 6: 0, 4: 8, 2: 10, 0: 12}
         values = RangeIndex(0, 10, 2)
         result = values.sort_values(key=lambda x: x.map(sort_order))
-        expected = Index([4, 8, 6, 0, 2], dtype="int64")
+        expected = Index([6, 8, 4, 2, 0], dtype="int64")
         tm.assert_index_equal(result, expected, check_exact=True)
 
+        # check this matches the Series.sort_values behavior
+        ser = values.to_series()
+        result2 = ser.sort_values(key=lambda x: x.map(sort_order))
+        tm.assert_series_equal(result2, expected.to_series(), check_exact=True)
+
     def test_range_index_rsub_by_const(self):
         # GH#53255
         result = 3 - RangeIndex(0, 4, 1)