Skip to content

Commit 0b7ae90

Browse files
committed
fixed up append
1 parent 7ab70c1 commit 0b7ae90

File tree

4 files changed

+72
-11
lines changed

4 files changed

+72
-11
lines changed

pandas/core/categorical.py

+4
Original file line numberDiff line numberDiff line change
@@ -233,6 +233,10 @@ def __init__(self, values, categories=None, ordered=False, name=None, fastpath=F
233233
cat = values
234234
if isinstance(values, ABCSeries):
235235
cat = values.values
236+
if isinstance(values, ABCCategoricalIndex):
237+
ordered = values.ordered
238+
cat = values.values
239+
236240
if categories is None:
237241
categories = cat.categories
238242
values = values.__array__()

pandas/core/index.py

+60-9
Original file line numberDiff line numberDiff line change
@@ -963,17 +963,13 @@ def __getitem__(self, key):
963963
else:
964964
return result
965965

966-
def append(self, other):
966+
def _ensure_compat_append(self, other):
967967
"""
968-
Append a collection of Index options together
969-
970-
Parameters
971-
----------
972-
other : Index or list/tuple of indices
968+
prepare the append
973969
974970
Returns
975971
-------
976-
appended : Index
972+
list of to_concat, name of result Index
977973
"""
978974
name = self.name
979975
to_concat = [self]
@@ -991,7 +987,21 @@ def append(self, other):
991987
to_concat = self._ensure_compat_concat(to_concat)
992988
to_concat = [x.values if isinstance(x, Index) else x
993989
for x in to_concat]
990+
return to_concat, name
991+
992+
def append(self, other):
993+
"""
994+
Append a collection of Index options together
994995
996+
Parameters
997+
----------
998+
other : Index or list/tuple of indices
999+
1000+
Returns
1001+
-------
1002+
appended : Index
1003+
"""
1004+
to_concat, name = self._ensure_compat_append(other)
9951005
return Index(np.concatenate(to_concat), name=name)
9961006

9971007
@staticmethod
@@ -2628,6 +2638,10 @@ def codes(self):
26282638
def categories(self):
26292639
return self._data.categories
26302640

2641+
@property
2642+
def ordered(self):
2643+
return self._data.ordered
2644+
26312645
def __contains__(self, key):
26322646
hash(key)
26332647
return key in self.categories
@@ -2760,11 +2774,48 @@ def insert(self, loc, item):
27602774

27612775
from pandas import Categorical
27622776
codes = self.codes
2763-
idx = np.concatenate(
2777+
codes = np.concatenate(
27642778
(codes[:loc], code, codes[loc:]))
2765-
cat = Categorical.from_codes(idx, categories=self.categories)
2779+
cat = Categorical.from_codes(codes, categories=self.categories)
27662780
return CategoricalIndex(cat, name=self.name)
27672781

2782+
def append(self, other):
2783+
"""
2784+
Append a collection of CategoricalIndex options together
2785+
2786+
Parameters
2787+
----------
2788+
other : Index or list/tuple of indices
2789+
2790+
Returns
2791+
-------
2792+
appended : Index
2793+
2794+
Raises
2795+
------
2796+
ValueError if other is not in the categories
2797+
"""
2798+
from pandas import Categorical
2799+
categories = self.categories
2800+
to_concat, name = self._ensure_compat_append(other)
2801+
2802+
def convert(c):
2803+
""" make sure that we have the same categories exactly """
2804+
if is_categorical_dtype(c):
2805+
if not c.categories.equals(categories):
2806+
raise ValueError("categories must match existing categories when appending")
2807+
else:
2808+
c = Categorical(c, categories)
2809+
if isnull(c).any():
2810+
raise ValueError("cannot append a non-category item to a CategoricalIndex")
2811+
2812+
return c
2813+
2814+
to_concat = [ convert(c) for c in to_concat ]
2815+
2816+
codes = np.concatenate([ c.codes for c in to_concat ])
2817+
cat = Categorical.from_codes(codes, categories=categories)
2818+
return CategoricalIndex(cat, name=name)
27682819

27692820
CategoricalIndex._add_numeric_methods_disabled()
27702821
CategoricalIndex._add_logical_methods_disabled()

pandas/tests/test_categorical.py

+6-1
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
import numpy as np
1212
import pandas as pd
1313

14-
from pandas import Categorical, Index, Series, DataFrame, PeriodIndex, Timestamp
14+
from pandas import Categorical, Index, Series, DataFrame, PeriodIndex, Timestamp, CategoricalIndex
1515

1616
from pandas.core.config import option_context
1717
import pandas.core.common as com
@@ -221,6 +221,11 @@ def f():
221221
c_old2 = Categorical([0, 1, 2, 0, 1, 2], [1, 2, 3])
222222
cat = Categorical([1,2], categories=[1,2,3])
223223

224+
def test_constructor_with_categorical_index(self):
225+
226+
ci = CategoricalIndex(list('aabbca'),categories=list('cab'))
227+
self.assertTrue(ci.values.equals(Categorical(ci)))
228+
224229
def test_constructor_with_generator(self):
225230
# This was raising an Error in isnull(single_val).any() because isnull returned a scalar
226231
# for a generator

pandas/tests/test_index.py

+2-1
Original file line numberDiff line numberDiff line change
@@ -1392,7 +1392,8 @@ def test_append(self):
13921392
result = ci.append([])
13931393
self.assertTrue(result.equals(ci))
13941394

1395-
# appending with different categories
1395+
# appending with different categories or reoreded is not ok
1396+
self.assertRaises(ValueError, lambda : ci.append(ci.values.set_categories(list('abcd'))))
13961397
self.assertRaises(ValueError, lambda : ci.append(ci.values.reorder_categories(list('abc'))))
13971398

13981399
# with objects

0 commit comments

Comments
 (0)