Skip to content

Commit 5f0caf0

Browse files
author
cloudboat
committed
ENH: Add insert_level method to MultiIndex with formatting fixes
1 parent 5b76304 commit 5f0caf0

File tree

2 files changed

+26
-69
lines changed

2 files changed

+26
-69
lines changed

pandas/core/indexes/multi.py

Lines changed: 0 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -4452,46 +4452,4 @@ def cartesian_product(X: list[np.ndarray]) -> list[np.ndarray]:
44524452
for i, x in enumerate(X)
44534453
]
44544454

4455-
def insert_level(self, position: int, value, name=None):
4456-
"""
4457-
Insert a new level at the specified position in the MultiIndex.
4458-
"""
4459-
if not isinstance(position, int):
4460-
raise TypeError("position must be an integer")
4461-
4462-
if position < 0 or position > self.nlevels:
4463-
raise ValueError(f"position must be between 0 and {self.nlevels}")
4464-
4465-
from pandas.core.construction import extract_array
4466-
from pandas.core.indexes.base import ensure_index
4467-
4468-
if not hasattr(value, '__iter__') or isinstance(value, str):
4469-
value = [value] * len(self)
4470-
else:
4471-
value = list(value)
4472-
if len(value) != len(self):
4473-
raise ValueError("Length of values must match length of index")
4474-
4475-
tuples = list(self)
4476-
4477-
new_tuples = []
4478-
for i, tup in enumerate(tuples):
4479-
if isinstance(tup, tuple):
4480-
new_tuple = list(tup)
4481-
new_tuple.insert(position, value[i])
4482-
new_tuples.append(tuple(new_tuple))
4483-
else:
4484-
new_tuple = [tup]
4485-
new_tuple.insert(position, value[i])
4486-
new_tuples.append(tuple(new_tuple))
4487-
4488-
if self.names is not None:
4489-
new_names = list(self.names)
4490-
else:
4491-
new_names = [None] * self.nlevels
4492-
4493-
new_names.insert(position, name)
4494-
4495-
from pandas import MultiIndex
4496-
return MultiIndex.from_tuples(new_tuples, names=new_names)
44974455

Lines changed: 26 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,62 +1,61 @@
11
import pytest
2+
23
import pandas as pd
3-
import numpy as np
44
import pandas._testing as tm
55

66

7-
87
class TestMultiIndexInsertLevel:
98

109
def setup_method(self):
1110
self.simple_idx = pd.MultiIndex.from_tuples(
12-
[('A', 1), ('B', 2), ('C', 3)], names=['level1', 'level2']
11+
[("A", 1), ("B", 2), ("C", 3)], names=["level1", "level2"]
1312
)
14-
self.empty_idx = pd.MultiIndex.from_tuples([], names=['level1', 'level2'])
13+
self.empty_idx = pd.MultiIndex.from_tuples([], names=["level1", "level2"])
1514

1615
def test_insert_level_basic(self):
17-
result = self.simple_idx.insert_level(0, 'new_value')
16+
result = self.simple_idx.insert_level(0, "new_value")
1817
expected = pd.MultiIndex.from_tuples(
19-
[('new_value', 'A', 1), ('new_value', 'B', 2), ('new_value', 'C', 3)],
20-
names=[None, 'level1', 'level2']
18+
[("new_value", "A", 1), ("new_value", "B", 2), ("new_value", "C", 3)],
19+
names=[None, "level1", "level2"]
2120
)
2221
tm.assert_index_equal(result, expected)
2322

24-
result = self.simple_idx.insert_level(1, 'middle')
23+
result = self.simple_idx.insert_level(1, "middle")
2524
expected = pd.MultiIndex.from_tuples(
26-
[('A', 'middle', 1), ('B', 'middle', 2), ('C', 'middle', 3)],
27-
names=['level1', None, 'level2']
25+
[("A", "middle", 1), ("B", "middle", 2), ("C", "middle", 3)],
26+
names=["level1", None, "level2"]
2827
)
2928
tm.assert_index_equal(result, expected)
3029

3130
def test_insert_level_with_different_values(self):
32-
new_values = ['X', 'Y', 'Z']
31+
new_values = ["X", "Y", "Z"]
3332
result = self.simple_idx.insert_level(1, new_values)
3433
expected = pd.MultiIndex.from_tuples(
35-
[('A', 'X', 1), ('B', 'Y', 2), ('C', 'Z', 3)],
36-
names=['level1', None, 'level2']
34+
[("A", "X", 1), ("B", "Y", 2), ("C", "Z", 3)],
35+
names=["level1", None, "level2"]
3736
)
3837
tm.assert_index_equal(result, expected)
3938

4039
def test_insert_level_with_name(self):
41-
result = self.simple_idx.insert_level(0, 'new_val', name='new_level')
42-
assert result.names[0] == 'new_level'
40+
result = self.simple_idx.insert_level(0, "new_val", name="new_level")
41+
assert result.names[0] == "new_level"
4342

4443
def test_insert_level_edge_positions(self):
45-
result_start = self.simple_idx.insert_level(0, 'start')
44+
result_start = self.simple_idx.insert_level(0, "start")
4645
assert result_start.nlevels == 3
4746

48-
result_end = self.simple_idx.insert_level(2, 'end')
47+
result_end = self.simple_idx.insert_level(2, "end")
4948
assert result_end.nlevels == 3
5049

5150
def test_insert_level_error_cases(self):
5251
with pytest.raises(ValueError, match="position must be between"):
53-
self.simple_idx.insert_level(5, 'invalid')
52+
self.simple_idx.insert_level(5, "invalid")
5453

5554
with pytest.raises(ValueError, match="position must be between"):
56-
self.simple_idx.insert_level(-1, 'invalid')
55+
self.simple_idx.insert_level(-1, "invalid")
5756

5857
with pytest.raises(ValueError, match="Length of values must match"):
59-
self.simple_idx.insert_level(1, ['too', 'few'])
58+
self.simple_idx.insert_level(1, ["too", "few"])
6059

6160
def test_insert_level_with_different_data_types(self):
6261
result_int = self.simple_idx.insert_level(1, 100)
@@ -71,24 +70,24 @@ def test_insert_level_with_different_data_types(self):
7170

7271
def test_insert_level_preserves_original(self):
7372
original = self.simple_idx.copy()
74-
result = self.simple_idx.insert_level(1, 'temp')
73+
result = self.simple_idx.insert_level(1, "temp")
7574

7675
tm.assert_index_equal(original, self.simple_idx)
7776

7877
assert result.nlevels == original.nlevels + 1
7978

8079
def test_debug_names():
8180
idx = pd.MultiIndex.from_tuples(
82-
[('A', 1), ('B', 2), ('C', 3)],
83-
names=['level1', 'level2']
81+
[("A", 1), ("B", 2), ("C", 3)],
82+
names=["level1", "level2"]
8483
)
8584
print("Original names:", idx.names)
8685

87-
result = idx.insert_level(0, 'new_value')
86+
result = idx.insert_level(0, "new_value")
8887
print("Result names:", result.names)
8988

9089
expected = pd.MultiIndex.from_tuples(
91-
[('new_value', 'A', 1), ('new_value', 'B', 2), ('new_value', 'C', 3)],
92-
names=[None, 'level1', 'level2']
90+
[("new_value", "A", 1), ("new_value", "B", 2), ("new_value", "C", 3)],
91+
names=[None, "level1", "level2"]
9392
)
94-
print("Expected names:", expected.names)
93+
print("Expected names:", expected.names)

0 commit comments

Comments
 (0)