Skip to content

Commit 43e251d

Browse files
charlesdong1991jreback
authored andcommitted
ENH: Add ignore_index to sort_index (#30578)
1 parent ba742da commit 43e251d

File tree

6 files changed

+134
-5
lines changed

6 files changed

+134
-5
lines changed

doc/source/whatsnew/v1.0.0.rst

+1
Original file line numberDiff line numberDiff line change
@@ -222,6 +222,7 @@ Other enhancements
222222
- DataFrame constructor preserve `ExtensionArray` dtype with `ExtensionArray` (:issue:`11363`)
223223
- :meth:`DataFrame.sort_values` and :meth:`Series.sort_values` have gained ``ignore_index`` keyword to be able to reset index after sorting (:issue:`30114`)
224224
- :meth:`DataFrame.to_markdown` and :meth:`Series.to_markdown` added (:issue:`11052`)
225+
- :meth:`DataFrame.sort_index` and :meth:`Series.sort_index` have gained ``ignore_index`` keyword to reset index (:issue:`30114`)
225226
- :meth:`DataFrame.drop_duplicates` has gained ``ignore_index`` keyword to reset index (:issue:`30114`)
226227
- Added new writer for exporting Stata dta files in version 118, ``StataWriter118``. This format supports exporting strings containing Unicode characters (:issue:`23573`)
227228
- :meth:`Series.map` now accepts ``collections.abc.Mapping`` subclasses as a mapper (:issue:`29733`)

pandas/core/frame.py

+5-1
Original file line numberDiff line numberDiff line change
@@ -1992,7 +1992,7 @@ def to_feather(self, path):
19921992
@Substitution(klass="DataFrame")
19931993
@Appender(_shared_docs["to_markdown"])
19941994
def to_markdown(
1995-
self, buf: Optional[IO[str]] = None, mode: Optional[str] = None, **kwargs,
1995+
self, buf: Optional[IO[str]] = None, mode: Optional[str] = None, **kwargs
19961996
) -> Optional[str]:
19971997
kwargs.setdefault("headers", "keys")
19981998
kwargs.setdefault("tablefmt", "pipe")
@@ -4883,6 +4883,7 @@ def sort_index(
48834883
kind="quicksort",
48844884
na_position="last",
48854885
sort_remaining=True,
4886+
ignore_index: bool = False,
48864887
):
48874888

48884889
# TODO: this can be combined with Series.sort_index impl as
@@ -4933,6 +4934,9 @@ def sort_index(
49334934
# reconstruct axis if needed
49344935
new_data.axes[baxis] = new_data.axes[baxis]._sort_levels_monotonic()
49354936

4937+
if ignore_index:
4938+
new_data.axes[1] = ibase.default_index(len(indexer))
4939+
49364940
if inplace:
49374941
return self._update_inplace(new_data)
49384942
else:

pandas/core/generic.py

+5
Original file line numberDiff line numberDiff line change
@@ -4185,6 +4185,7 @@ def sort_index(
41854185
kind: str = "quicksort",
41864186
na_position: str = "last",
41874187
sort_remaining: bool_t = True,
4188+
ignore_index: bool_t = False,
41884189
):
41894190
"""
41904191
Sort object by labels (along an axis).
@@ -4211,6 +4212,10 @@ def sort_index(
42114212
sort_remaining : bool, default True
42124213
If True and sorting by level and index is multilevel, sort by other
42134214
levels too (in order) after sorting by specified level.
4215+
ignore_index : bool, default False
4216+
If True, the resulting axis will be labeled 0, 1, …, n - 1.
4217+
4218+
.. versionadded:: 1.0.0
42144219
42154220
Returns
42164221
-------

pandas/core/series.py

+10-4
Original file line numberDiff line numberDiff line change
@@ -1418,7 +1418,7 @@ def to_string(
14181418
@Substitution(klass="Series")
14191419
@Appender(generic._shared_docs["to_markdown"])
14201420
def to_markdown(
1421-
self, buf: Optional[IO[str]] = None, mode: Optional[str] = None, **kwargs,
1421+
self, buf: Optional[IO[str]] = None, mode: Optional[str] = None, **kwargs
14221422
) -> Optional[str]:
14231423
return self.to_frame().to_markdown(buf, mode, **kwargs)
14241424

@@ -2948,6 +2948,7 @@ def sort_index(
29482948
kind="quicksort",
29492949
na_position="last",
29502950
sort_remaining=True,
2951+
ignore_index: bool = False,
29512952
):
29522953
"""
29532954
Sort Series by index labels.
@@ -2976,6 +2977,10 @@ def sort_index(
29762977
sort_remaining : bool, default True
29772978
If True and sorting by level and index is multilevel, sort by other
29782979
levels too (in order) after sorting by specified level.
2980+
ignore_index : bool, default False
2981+
If True, the resulting axis will be labeled 0, 1, …, n - 1.
2982+
2983+
.. versionadded:: 1.0.0
29792984
29802985
Returns
29812986
-------
@@ -3103,6 +3108,9 @@ def sort_index(
31033108
new_values = self._values.take(indexer)
31043109
result = self._constructor(new_values, index=new_index)
31053110

3111+
if ignore_index:
3112+
result.index = ibase.default_index(len(result))
3113+
31063114
if inplace:
31073115
self._update_inplace(result)
31083116
else:
@@ -4463,9 +4471,7 @@ def to_period(self, freq=None, copy=True):
44634471
hist = pandas.plotting.hist_series
44644472

44654473

4466-
Series._setup_axes(
4467-
["index"], docs={"index": "The index (axis labels) of the Series."},
4468-
)
4474+
Series._setup_axes(["index"], docs={"index": "The index (axis labels) of the Series."})
44694475
Series._add_numeric_operations()
44704476
Series._add_series_or_dataframe_operations()
44714477

pandas/tests/frame/methods/test_sort_index.py

+82
Original file line numberDiff line numberDiff line change
@@ -229,3 +229,85 @@ def test_sort_index_intervalindex(self):
229229
)
230230
result = result.columns.levels[1].categories
231231
tm.assert_index_equal(result, expected)
232+
233+
@pytest.mark.parametrize(
234+
"original_dict, sorted_dict, ascending, ignore_index, output_index",
235+
[
236+
({"A": [1, 2, 3]}, {"A": [2, 3, 1]}, False, True, [0, 1, 2]),
237+
({"A": [1, 2, 3]}, {"A": [1, 3, 2]}, True, True, [0, 1, 2]),
238+
({"A": [1, 2, 3]}, {"A": [2, 3, 1]}, False, False, [5, 3, 2]),
239+
({"A": [1, 2, 3]}, {"A": [1, 3, 2]}, True, False, [2, 3, 5]),
240+
],
241+
)
242+
def test_sort_index_ignore_index(
243+
self, original_dict, sorted_dict, ascending, ignore_index, output_index
244+
):
245+
# GH 30114
246+
original_index = [2, 5, 3]
247+
df = DataFrame(original_dict, index=original_index)
248+
expected_df = DataFrame(sorted_dict, index=output_index)
249+
250+
sorted_df = df.sort_index(ascending=ascending, ignore_index=ignore_index)
251+
tm.assert_frame_equal(sorted_df, expected_df)
252+
tm.assert_frame_equal(df, DataFrame(original_dict, index=original_index))
253+
254+
# Test when inplace is True
255+
copied_df = df.copy()
256+
copied_df.sort_index(
257+
ascending=ascending, ignore_index=ignore_index, inplace=True
258+
)
259+
tm.assert_frame_equal(copied_df, expected_df)
260+
tm.assert_frame_equal(df, DataFrame(original_dict, index=original_index))
261+
262+
@pytest.mark.parametrize(
263+
"original_dict, sorted_dict, ascending, ignore_index, output_index",
264+
[
265+
(
266+
{"M1": [1, 2], "M2": [3, 4]},
267+
{"M1": [1, 2], "M2": [3, 4]},
268+
True,
269+
True,
270+
[0, 1],
271+
),
272+
(
273+
{"M1": [1, 2], "M2": [3, 4]},
274+
{"M1": [2, 1], "M2": [4, 3]},
275+
False,
276+
True,
277+
[0, 1],
278+
),
279+
(
280+
{"M1": [1, 2], "M2": [3, 4]},
281+
{"M1": [1, 2], "M2": [3, 4]},
282+
True,
283+
False,
284+
MultiIndex.from_tuples([[2, 1], [3, 4]], names=list("AB")),
285+
),
286+
(
287+
{"M1": [1, 2], "M2": [3, 4]},
288+
{"M1": [2, 1], "M2": [4, 3]},
289+
False,
290+
False,
291+
MultiIndex.from_tuples([[3, 4], [2, 1]], names=list("AB")),
292+
),
293+
],
294+
)
295+
def test_sort_index_ignore_index_multi_index(
296+
self, original_dict, sorted_dict, ascending, ignore_index, output_index
297+
):
298+
# GH 30114, this is to test ignore_index on MulitIndex of index
299+
mi = MultiIndex.from_tuples([[2, 1], [3, 4]], names=list("AB"))
300+
df = DataFrame(original_dict, index=mi)
301+
expected_df = DataFrame(sorted_dict, index=output_index)
302+
303+
sorted_df = df.sort_index(ascending=ascending, ignore_index=ignore_index)
304+
tm.assert_frame_equal(sorted_df, expected_df)
305+
tm.assert_frame_equal(df, DataFrame(original_dict, index=mi))
306+
307+
# Test when inplace is True
308+
copied_df = df.copy()
309+
copied_df.sort_index(
310+
ascending=ascending, ignore_index=ignore_index, inplace=True
311+
)
312+
tm.assert_frame_equal(copied_df, expected_df)
313+
tm.assert_frame_equal(df, DataFrame(original_dict, index=mi))

pandas/tests/series/methods/test_sort_index.py

+31
Original file line numberDiff line numberDiff line change
@@ -135,3 +135,34 @@ def test_sort_index_intervals(self):
135135
[3, 2, 1, np.nan], IntervalIndex.from_arrays([3, 2, 1, 0], [4, 3, 2, 1])
136136
)
137137
tm.assert_series_equal(result, expected)
138+
139+
@pytest.mark.parametrize(
140+
"original_list, sorted_list, ascending, ignore_index, output_index",
141+
[
142+
([2, 3, 6, 1], [2, 3, 6, 1], True, True, [0, 1, 2, 3]),
143+
([2, 3, 6, 1], [2, 3, 6, 1], True, False, [0, 1, 2, 3]),
144+
([2, 3, 6, 1], [1, 6, 3, 2], False, True, [0, 1, 2, 3]),
145+
([2, 3, 6, 1], [1, 6, 3, 2], False, False, [3, 2, 1, 0]),
146+
],
147+
)
148+
def test_sort_index_ignore_index(
149+
self, original_list, sorted_list, ascending, ignore_index, output_index
150+
):
151+
# GH 30114
152+
ser = Series(original_list)
153+
expected = Series(sorted_list, index=output_index)
154+
155+
# Test when inplace is False
156+
sorted_sr = ser.sort_index(ascending=ascending, ignore_index=ignore_index)
157+
tm.assert_series_equal(sorted_sr, expected)
158+
159+
tm.assert_series_equal(ser, Series(original_list))
160+
161+
# Test when inplace is True
162+
copied_sr = ser.copy()
163+
copied_sr.sort_index(
164+
ascending=ascending, ignore_index=ignore_index, inplace=True
165+
)
166+
tm.assert_series_equal(copied_sr, expected)
167+
168+
tm.assert_series_equal(ser, Series(original_list))

0 commit comments

Comments
 (0)