Skip to content

Commit 880a8ea

Browse files
committed
ENH: Add HashableIndexes to core/index.py
1 parent 3349ea7 commit 880a8ea

File tree

2 files changed

+73
-1
lines changed

2 files changed

+73
-1
lines changed

pandas/core/common.py

+25
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99

1010
import itertools
1111
from datetime import datetime
12+
import types
1213

1314
from numpy.lib.format import read_array, write_array
1415
import numpy as np
@@ -42,6 +43,30 @@ class AmbiguousIndexError(PandasError, KeyError):
4243
pass
4344

4445

46+
def bind_method(cls, name, func):
47+
"""Bind a method to class, python 2 and python 3 compatible.
48+
49+
Parameters
50+
----------
51+
52+
cls : type
53+
class to receive bound method
54+
name : basestring
55+
name of method on class instance
56+
func : function
57+
function to be bound as method
58+
59+
60+
Returns
61+
-------
62+
None
63+
"""
64+
# only python 2 has bound/unbound method issue
65+
if not py3compat.PY3:
66+
setattr(cls, name, types.MethodType(func, None, cls))
67+
else:
68+
setattr(cls, name, func)
69+
4570
_POSSIBLY_CAST_DTYPES = set([ np.dtype(t) for t in ['M8[ns]','m8[ns]','O','int8','uint8','int16','uint16','int32','uint32','int64','uint64'] ])
4671
_NS_DTYPE = np.dtype('M8[ns]')
4772
_TD_DTYPE = np.dtype('m8[ns]')

pandas/core/index.py

+48-1
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
from pandas.lib import Timestamp
1212

1313
from pandas.util.decorators import cache_readonly
14-
from pandas.core.common import isnull
14+
from pandas.core.common import isnull, bind_method
1515
import pandas.core.common as com
1616
from pandas.util import py3compat
1717
from pandas.core.config import get_option
@@ -2688,6 +2688,53 @@ def _wrap_joined_index(self, joined, other):
26882688
return MultiIndex.from_tuples(joined, names=names)
26892689

26902690

2691+
def hashable_class_factory(klass, hash_func=None):
2692+
"""Creates Hashable Class for given Index type
2693+
and adds `ashashable` method to the Index"""
2694+
2695+
class HashableIndexMixin(object):
2696+
"""
2697+
Implements hashing methods...note that this is
2698+
very crude, and *only* works if it's mixed into a parent
2699+
class that is a subclass of (or just is) an index
2700+
"""
2701+
2702+
def __init__(self, index):
2703+
self._index = index
2704+
2705+
def __eq__(self, other):
2706+
if issubclass(other, klass):
2707+
return (self.values == other.values).all()
2708+
else:
2709+
return False
2710+
2711+
if hash_func:
2712+
__hash__ = hash_func
2713+
else:
2714+
def __hash__(self):
2715+
return hash(str(self))
2716+
2717+
# should this be a property??
2718+
def asindex(self):
2719+
return self._index
2720+
2721+
HashableClass = type("Hashable{klass}".format(klass=klass.__name__), (HashableIndexMixin, klass))
2722+
2723+
def ashashable(self):
2724+
"""convert {klass} to a hashable type that
2725+
can be used for key/value lookup
2726+
"""
2727+
return HashableClass(self)
2728+
2729+
ashashable.__doc__ = ashashable.__doc__.format(klass=klass.__name__)
2730+
bind_method(klass, "ashashable", ashashable)
2731+
2732+
return HashableClass
2733+
2734+
HashableIndex = hashable_class_factory(Index)
2735+
HashableInt64Index = hashable_class_factory(Int64Index)
2736+
HashableMultiIndex = hashable_class_factory(MultiIndex)
2737+
26912738
# For utility purposes
26922739

26932740
def _sparsify(label_list, start=0,sentinal=''):

0 commit comments

Comments
 (0)