Skip to content

Commit

Permalink
REF: Avoid code duplication in RangeIndex.append
Browse files Browse the repository at this point in the history
  • Loading branch information
toobaz committed Aug 10, 2017
1 parent 5029592 commit d5c7d77
Show file tree
Hide file tree
Showing 3 changed files with 47 additions and 57 deletions.
6 changes: 5 additions & 1 deletion pandas/core/dtypes/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
from .generic import (ABCCategorical, ABCPeriodIndex,
ABCDatetimeIndex, ABCSeries,
ABCSparseArray, ABCSparseSeries, ABCCategoricalIndex,
ABCIndexClass)
ABCIndexClass, ABCRangeIndex)
from .inference import is_string_like
from .inference import * # noqa

Expand Down Expand Up @@ -220,6 +220,10 @@ def is_categorical(arr):
return isinstance(arr, ABCCategorical) or is_categorical_dtype(arr)


def is_range(arr):
return isinstance(arr, ABCRangeIndex)


def is_datetimetz(arr):
"""
Check whether an array-like is a datetime array-like with a timezone
Expand Down
38 changes: 38 additions & 0 deletions pandas/core/dtypes/concat.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
is_object_dtype,
is_bool_dtype,
is_dtype_equal,
is_range,
_NS_DTYPE,
_TD_DTYPE)
from pandas.core.dtypes.generic import (
Expand Down Expand Up @@ -45,6 +46,8 @@ def get_dtype_kinds(l):
# if to_concat contains different tz,
# the result must be object dtype
typ = str(arr.dtype)
elif is_range(arr):
typ = 'range'
elif is_datetime64_dtype(dtype):
typ = 'datetime'
elif is_timedelta64_dtype(dtype):
Expand Down Expand Up @@ -559,3 +562,38 @@ def convert_sparse(x, axis):
# coerce to object if needed
result = result.astype('object')
return result


def _concat_indexes_same_dtype_rangeindex(indexes):

start = step = next = None

for obj in indexes:
if not len(obj):
continue

if start is None:
# This is set by the first non-empty index
start = obj._start
if step is None and len(obj) > 1:
step = obj._step
elif step is None:
# First non-empty index had only one element
if obj._start == start:
return _concat_index_asobject(indexes)
step = obj._start - start

non_consecutive = ((step != obj._step and len(obj) > 1) or
(next is not None and obj._start != next))
if non_consecutive:
# Not nice... but currently what happens in NumericIndex:
return _concat_index_asobject(indexes)

if step is not None:
next = obj[-1] + step

if start is None:
start = obj._start
step = obj._step
stop = obj._stop if next is None else next
return indexes[0].__class__(start, stop, step)
60 changes: 4 additions & 56 deletions pandas/core/indexes/range.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
from pandas.compat.numpy import function as nv
from pandas.core.indexes.base import Index, _index_shared_docs
from pandas.util._decorators import Appender, cache_readonly
import pandas.core.dtypes.concat as _concat
import pandas.core.indexes.base as ibase

from pandas.core.indexes.numeric import Int64Index
Expand Down Expand Up @@ -443,62 +444,9 @@ def join(self, other, how='left', level=None, return_indexers=False,
return super(RangeIndex, self).join(other, how, level, return_indexers,
sort)

def append(self, other):
"""
Append a collection of Index options together
Parameters
----------
other : Index or list/tuple of indices
Returns
-------
appended : RangeIndex if all indexes are consecutive RangeIndexes,
otherwise Int64Index or Index
"""

to_concat = [self]

if isinstance(other, (list, tuple)):
to_concat = to_concat + list(other)
else:
to_concat.append(other)

if not all([isinstance(i, RangeIndex) for i in to_concat]):
return super(RangeIndex, self).append(other)

start = step = next = None

for obj in to_concat:
if not len(obj):
continue

if start is None:
# This is set by the first non-empty index
start = obj._start
if step is None and len(obj) > 1:
step = obj._step
elif step is None:
# First non-empty index had only one element
if obj._start == start:
return super(RangeIndex, self).append(other)
step = obj._start - start

non_consecutive = ((step != obj._step and len(obj) > 1) or
(next is not None and obj._start != next))
if non_consecutive:
return super(RangeIndex, self).append(other)

if step is not None:
next = obj[-1] + step

if start is None:
start = obj._start
step = obj._step
stop = obj._stop if next is None else next
names = set([obj.name for obj in to_concat])
name = None if len(names) > 1 else self.name
return RangeIndex(start, stop, step, name=name)
def _append_same_dtype(self, indexes, name):
return _concat._concat_indexes_same_dtype_rangeindex(indexes
).rename(name)

def __len__(self):
"""
Expand Down

0 comments on commit d5c7d77

Please sign in to comment.