Skip to content

Commit 5893f95

Browse files
ENH: added df/series.sort_values(key=...) and df/series.sort_index(key=...) functionality
1 parent cb05112 commit 5893f95

File tree

2 files changed

+34
-6
lines changed

2 files changed

+34
-6
lines changed

pandas/core/frame.py

+17-4
Original file line numberDiff line numberDiff line change
@@ -4715,6 +4715,7 @@ def sort_values(
47154715
inplace=False,
47164716
kind="quicksort",
47174717
na_position="last",
4718+
key = None
47184719
):
47194720
inplace = validate_bool_kwarg(inplace, "inplace")
47204721
axis = self._get_axis_number(axis)
@@ -4728,7 +4729,12 @@ def sort_values(
47284729
if len(by) > 1:
47294730
from pandas.core.sorting import lexsort_indexer
47304731

4731-
keys = [self._get_label_or_level_values(x, axis=axis) for x in by]
4732+
if key is not None:
4733+
key_func = np.vectorize(key)
4734+
keys = [key_func(self._get_label_or_level_values(x, axis=axis)) for x in by]
4735+
else:
4736+
keys = [self._get_label_or_level_values(x, axis=axis) for x in by]
4737+
47324738
indexer = lexsort_indexer(keys, orders=ascending, na_position=na_position)
47334739
indexer = ensure_platform_int(indexer)
47344740
else:
@@ -4737,6 +4743,10 @@ def sort_values(
47374743
by = by[0]
47384744
k = self._get_label_or_level_values(by, axis=axis)
47394745

4746+
if key is not None:
4747+
key_func = np.vectorize(key)
4748+
k = key_func(k)
4749+
47404750
if isinstance(ascending, (tuple, list)):
47414751
ascending = ascending[0]
47424752

@@ -4764,6 +4774,7 @@ def sort_index(
47644774
kind="quicksort",
47654775
na_position="last",
47664776
sort_remaining=True,
4777+
key=None
47674778
):
47684779

47694780
# TODO: this can be combined with Series.sort_index impl as
@@ -4773,21 +4784,23 @@ def sort_index(
47734784

47744785
axis = self._get_axis_number(axis)
47754786
labels = self._get_axis(axis)
4776-
4787+
if key is not None:
4788+
labels = labels.map(key)
4789+
47774790
# make sure that the axis is lexsorted to start
47784791
# if not we need to reconstruct to get the correct indexer
47794792
labels = labels._sort_levels_monotonic()
47804793
if level is not None:
4781-
47824794
new_axis, indexer = labels.sortlevel(
47834795
level, ascending=ascending, sort_remaining=sort_remaining
47844796
)
47854797

47864798
elif isinstance(labels, ABCMultiIndex):
47874799
from pandas.core.sorting import lexsort_indexer
47884800

4801+
codes = labels._get_codes_for_sorting()
47894802
indexer = lexsort_indexer(
4790-
labels._get_codes_for_sorting(),
4803+
codes,
47914804
orders=ascending,
47924805
na_position=na_position,
47934806
)

pandas/core/series.py

+17-2
Original file line numberDiff line numberDiff line change
@@ -2835,6 +2835,7 @@ def sort_values(
28352835
inplace=False,
28362836
kind="quicksort",
28372837
na_position="last",
2838+
key=None
28382839
):
28392840
"""
28402841
Sort by the values.
@@ -2952,6 +2953,10 @@ def sort_values(
29522953
)
29532954

29542955
def _try_kind_sort(arr):
2956+
if key is not None:
2957+
key_func = np.vectorize(key)
2958+
arr = key_func(arr)
2959+
29552960
# easier to ask forgiveness than permission
29562961
try:
29572962
# if kind==mergesort, it can fail for object dtype
@@ -3011,6 +3016,7 @@ def sort_index(
30113016
kind="quicksort",
30123017
na_position="last",
30133018
sort_remaining=True,
3019+
key=None
30143020
):
30153021
"""
30163022
Sort Series by index labels.
@@ -3128,17 +3134,22 @@ def sort_index(
31283134
# Validate the axis parameter
31293135
self._get_axis_number(axis)
31303136
index = self.index
3131-
3137+
if key is not None:
3138+
index = index.map(key)
3139+
31323140
if level is not None:
31333141
new_index, indexer = index.sortlevel(
31343142
level, ascending=ascending, sort_remaining=sort_remaining
31353143
)
3144+
31363145
elif isinstance(index, MultiIndex):
31373146
from pandas.core.sorting import lexsort_indexer
31383147

31393148
labels = index._sort_levels_monotonic()
3149+
codes = labels._get_codes_for_sorting()
3150+
31403151
indexer = lexsort_indexer(
3141-
labels._get_codes_for_sorting(),
3152+
codes,
31423153
orders=ascending,
31433154
na_position=na_position,
31443155
)
@@ -3155,6 +3166,10 @@ def sort_index(
31553166
else:
31563167
return self.copy()
31573168

3169+
if key is not None:
3170+
key_func = np.vectorize(key)
3171+
index = key_func(index)
3172+
31583173
indexer = nargsort(
31593174
index, kind=kind, ascending=ascending, na_position=na_position
31603175
)

0 commit comments

Comments
 (0)