diff --git a/awkward/array/base.py b/awkward/array/base.py index f609f56f..071dc330 100644 --- a/awkward/array/base.py +++ b/awkward/array/base.py @@ -34,14 +34,31 @@ import awkward.type import awkward.util +class At(object): + def __init__(self, array): + self._array = array + + def __repr__(self): + return "= node.counts.reshape(-1, 1)).any(): + raise IndexError("index in jagged subdimension is out of bounds") + index = (index.reshape(-1, len(head)) + self._starts.reshape(-1, 1)).reshape(-1) + node = node._content[index].reshape(-1, len(head)) + + elif len(head.shape) == 1 and issubclass(head.dtype.type, (awkward.util.numpy.bool, awkward.util.numpy.bool_)): + node = node.regular()[:, head] + + else: + raise TypeError("cannot interpret shape {0}, dtype {1} as a fancy index or mask".format(head.shape, head.dtype)) return node[tail] @@ -811,7 +824,7 @@ def argdistincts(self): def distincts(self): return self.pairs(same=False) - def argpairs(self, same=True): + def _argpairs(self, same=True): import awkward.array.table self._valid() @@ -839,8 +852,11 @@ def argpairs(self, same=True): return out + def argpairs(self, same=True): + return self._argpairs(same=same) - self._starts + def pairs(self, same=True): - argpairs = self.argpairs(same=same) + argpairs = self._argpairs(same=same) left = argpairs._content["0"] right = argpairs._content["1"] @@ -848,7 +864,7 @@ def pairs(self, same=True): out._parents = argpairs._parents return out - def argcross(self, other): + def _argcross(self, other): import awkward.array.table self._valid() @@ -873,10 +889,13 @@ def argcross(self, other): out._parents = parents return out + def argcross(self, other): + return self._argcross(other) - self._starts + def cross(self, other): import awkward.array.table - argcross = self.argcross(other) + argcross = self._argcross(other) left, right = argcross._content._content.values() fields = [other._content[right]] @@ -895,7 +914,9 @@ def _canuseoffset(self): return offsetsaliased(self._starts, self._stops) or (len(self._starts.shape) == 1 and awkward.util.numpy.array_equal(self._starts[1:], self._stops[:-1])) def flatten(self): - if self._canuseoffset(): + if len(self) == 0: + return self._content[0:0] + elif self._canuseoffset(): return self._content[self._starts[0]:self._stops[-1]] else: offsets = counts2offsets(self.counts.reshape(-1)) @@ -914,7 +935,7 @@ def any(self): else: content = self._content != 0 - out = awkward.util.numpy.empty(self._starts.shape + content.shape[1:], dtype=content.dtype) + out = awkward.util.numpy.empty(self._starts.shape + content.shape[1:], dtype=awkward.BOOLTYPE) nonterminal = self.offsets[self.offsets != self.offsets[-1]] if os.name == "nt": # Windows Numpy reduceat requires 32-bit indexes nonterminal = nonterminal.astype(awkward.util.numpy.int32) @@ -935,7 +956,7 @@ def all(self): else: content = self._content != 0 - out = awkward.util.numpy.empty(self._starts.shape + content.shape[1:], dtype=content.dtype) + out = awkward.util.numpy.empty(self._starts.shape + content.shape[1:], dtype=awkward.BOOLTYPE) nonterminal = self.offsets[self.offsets != self.offsets[-1]] if os.name == "nt": # Windows Numpy reduceat requires 32-bit indexes nonterminal = nonterminal.astype(awkward.util.numpy.int32) diff --git a/awkward/array/table.py b/awkward/array/table.py index a353f82a..7c1500ba 100644 --- a/awkward/array/table.py +++ b/awkward/array/table.py @@ -55,8 +55,9 @@ def __init__(self, table, index): def __repr__(self): return "<{0} {1}>".format(self._table.rowname, self._index) - def __hasattr__(self, name): - return name in self._table._content or "_" + name in self._table._content + @property + def at(self): + return awkward.array.base.At(self) def __contains__(self, name): return name in self._table._content @@ -64,13 +65,6 @@ def __contains__(self, name): def tolist(self): return dict((n, self._table._try_tolist(x[self._index])) for n, x in self._table._content.items()) - def __getattr__(self, name): - content = self._table._content.get("_" + name, None) - if content is not None: - return content[self._index] - - raise AttributeError("{0} is not a column in this {1}".format(repr(name), self._table.rowname)) - def __getitem__(self, where): if isinstance(where, awkward.util.string): try: @@ -344,7 +338,7 @@ def _newslice(self, head): if head < 0: head += length if not 0 <= head < length: - IndexError("index {0} out of bounds for length {1}".format(original_head, length)) + raise IndexError("index {0} out of bounds for length {1}".format(original_head, length)) return head elif isinstance(self._view, tuple): @@ -352,7 +346,7 @@ def _newslice(self, head): if head < 0: head += mylength if not 0 <= head < mylength: - IndexError("index {0} out of bounds for length {1}".format(original_head, mylength)) + raise IndexError("index {0} out of bounds for length {1}".format(original_head, mylength)) return mystart + mystep*head else: @@ -360,7 +354,7 @@ def _newslice(self, head): if head < 0: head += length if not 0 <= head < length: - IndexError("index {0} out of bounds for length {1}".format(original_head, length)) + raise IndexError("index {0} out of bounds for length {1}".format(original_head, length)) return self._view[head] elif isinstance(head, slice): diff --git a/awkward/version.py b/awkward/version.py index a68d668b..4fa43f41 100644 --- a/awkward/version.py +++ b/awkward/version.py @@ -30,7 +30,7 @@ import re -__version__ = "0.4.5" +__version__ = "0.5.0" version = __version__ version_info = tuple(re.split(r"[-\.]", __version__)) diff --git a/tests/test_methods.py b/tests/test_methods.py index b0c6cb34..12ae49e6 100644 --- a/tests/test_methods.py +++ b/tests/test_methods.py @@ -116,17 +116,14 @@ def __add__(self, other): def __radd__(self, other): return self._type_op(operator.add, other, True) - class TypeArray(TypeArrayMethods, awkward.ObjectArray): def __init__(self, x): self._initObjectArray(awkward.Table()) self["x"] = x - class Type(TypeMethods): def __init__(self, x): self._x = x - counts = np.array([1, 4, 2, 0, 15]) x = np.arange(np.sum(counts)) @@ -150,5 +147,4 @@ def __init__(self, x): JaggedTypeArray = awkward.Methods.mixin(TypeArrayMethods, awkward.JaggedArray) jagged_array = JaggedTypeArray.fromcounts(counts, array) assert np.all(jagged_array.x.flatten() == x) - assert np.all(jagged_array.pairs()._0.x.counts == counts*(counts+1)//2) - + assert np.all(jagged_array.pairs().at(0).x.counts == counts*(counts+1)//2)