Skip to content

Commit e22f05f

Browse files
committed
implemented LArray.keys, LArray.values and LArray.items
1 parent fe90bd4 commit e22f05f

File tree

4 files changed

+435
-1
lines changed

4 files changed

+435
-1
lines changed

doc/source/api.rst

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -232,6 +232,7 @@ LArray
232232
* :ref:`la_sorting`
233233
* :ref:`la_reshaping`
234234
* :ref:`la_testing`
235+
* :ref:`la_iter`
235236
* :ref:`la_op`
236237
* :ref:`la_misc`
237238
* :ref:`la_to_pandas`
@@ -425,6 +426,18 @@ Testing/Searching
425426
LArray.labelofmax
426427
LArray.indexofmax
427428

429+
.. _la_iter:
430+
431+
Iterating
432+
---------
433+
434+
.. autosummary::
435+
:toctree: _generated/
436+
437+
LArray.keys
438+
LArray.values
439+
LArray.items
440+
428441
.. _la_op:
429442

430443
Operators

doc/source/changes/version_0_30.rst.inc

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,9 @@ New features
120120
a_b a0_b1 a1_b2
121121
1 5
122122

123+
* implemented :py:obj:`LArray.keys()`, :py:obj:`LArray.values()` and :py:obj:`LArray.items()`
124+
methods to respectively loop on an array labels, values or (key, value) pairs.
125+
123126
* implemented :py:obj:`Axis.apply()` method to transform an axis labels by a function and return a new Axis.
124127

125128
>>> sex = Axis('sex=MALE,FEMALE')

larray/core/array.py

Lines changed: 280 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3141,6 +3141,285 @@ def indicesofsorted(self, axis=None, ascending=True, kind='quicksort'):
31413141

31423142
posargsort = renamed_to(indicesofsorted, 'posargsort')
31433143

3144+
# TODO: implement keys_by
3145+
# XXX: implement expand=True? Unsure it is necessary now that we have zip_array_*
3146+
def keys(self, axes=None, ascending=True):
3147+
r"""Returns a view on the array labels along axes.
3148+
3149+
Parameters
3150+
----------
3151+
axes : int, str or Axis or tuple of them, optional
3152+
Axis or axes along which to iterate and in which order. Defaults to None (all axes in the order they are
3153+
in the array).
3154+
ascending : bool, optional
3155+
Whether or not to iterate the axes in ascending order (from start to end). Defaults to True.
3156+
3157+
Returns
3158+
-------
3159+
Sequence
3160+
An object you can iterate (loop) on and index by position to get the Nth label along axes.
3161+
3162+
Examples
3163+
--------
3164+
First, define a small helper function to make the following examples more readable.
3165+
3166+
>>> def str_key(key):
3167+
... return tuple(str(k) for k in key)
3168+
3169+
Then create a test array:
3170+
3171+
>>> arr = ndtest((2, 2))
3172+
>>> arr
3173+
a\b b0 b1
3174+
a0 0 1
3175+
a1 2 3
3176+
3177+
By default it iterates on all axes, in the order they are in the array.
3178+
3179+
>>> for key in arr.keys():
3180+
... # print both the actual key object, and a (nicer) string representation
3181+
... print(key, "->", str_key(key))
3182+
(a.i[0], b.i[0]) -> ('a0', 'b0')
3183+
(a.i[0], b.i[1]) -> ('a0', 'b1')
3184+
(a.i[1], b.i[0]) -> ('a1', 'b0')
3185+
(a.i[1], b.i[1]) -> ('a1', 'b1')
3186+
>>> for key in arr.keys(ascending=False):
3187+
... print(str_key(key))
3188+
('a1', 'b1')
3189+
('a1', 'b0')
3190+
('a0', 'b1')
3191+
('a0', 'b0')
3192+
3193+
but you can specify another axis order:
3194+
3195+
>>> for key in arr.keys(('b', 'a')):
3196+
... print(str_key(key))
3197+
('b0', 'a0')
3198+
('b0', 'a1')
3199+
('b1', 'a0')
3200+
('b1', 'a1')
3201+
3202+
One can specify less axes than the array has:
3203+
3204+
>>> # iterate on the "b" axis, that is return each label along the "b" axis
3205+
... for key in arr.keys('b'):
3206+
... print(str_key(key))
3207+
('b0',)
3208+
('b1',)
3209+
3210+
One can also access elements of the key sequence directly, instead of iterating over it. Say we want to
3211+
retrieve the first and last keys of our array, we could write:
3212+
3213+
>>> keys = arr.keys()
3214+
>>> first_key = keys[0]
3215+
>>> str_key(first_key)
3216+
('a0', 'b0')
3217+
>>> last_key = keys[-1]
3218+
>>> str_key(last_key)
3219+
('a1', 'b1')
3220+
"""
3221+
return self.axes.iter_labels(axes, ascending=ascending)
3222+
3223+
# TODO: implement values_by
3224+
def values(self, axes=None, ascending=True, expand=False):
3225+
r"""Returns a view on the values of the array along axes.
3226+
3227+
Parameters
3228+
----------
3229+
axes : int, str or Axis or tuple of them, optional
3230+
Axis or axes along which to iterate and in which order. Defaults to None (all axes in the order they are
3231+
in the array).
3232+
ascending : bool, optional
3233+
Whether or not to iterate the axes in ascending order (from start to end). Defaults to True.
3234+
expand : bool, optional
3235+
Whether or not to expand array using axes. This allows one to iterate on axes which do not exist in
3236+
the array, which is useful when iterating on several arrays with different axes. Defaults to False.
3237+
3238+
Returns
3239+
-------
3240+
Sequence
3241+
An object you can iterate (loop) on and index by position.
3242+
3243+
Examples
3244+
--------
3245+
>>> arr = ndtest((2, 2))
3246+
>>> arr
3247+
a\b b0 b1
3248+
a0 0 1
3249+
a1 2 3
3250+
3251+
By default it iterates on all axes, in the order they are in the array.
3252+
3253+
>>> for value in arr.values():
3254+
... print(value)
3255+
0
3256+
1
3257+
2
3258+
3
3259+
>>> for value in arr.values(ascending=False):
3260+
... print(value)
3261+
3
3262+
2
3263+
1
3264+
0
3265+
3266+
but you can specify another axis order:
3267+
3268+
>>> for value in arr.values(('b', 'a')):
3269+
... print(value)
3270+
0
3271+
2
3272+
1
3273+
3
3274+
3275+
When you specify less axes than the array has, you get arrays back:
3276+
3277+
>>> # iterate on the "b" axis, that is return the (sub)array for each label along the "b" axis
3278+
... for value in arr.values('b'):
3279+
... print(value)
3280+
a a0 a1
3281+
0 2
3282+
a a0 a1
3283+
1 3
3284+
>>> # iterate on the "b" axis, that is return the (sub)array for each label along the "b" axis
3285+
... for value in arr.values('b', ascending=False):
3286+
... print(value)
3287+
a a0 a1
3288+
1 3
3289+
a a0 a1
3290+
0 2
3291+
>>> # iterate on the "c" axis, which does not exist in arr, that is return arr for each label along the "c" axis
3292+
... for value in arr.values('c=c0,c1', expand=True):
3293+
... print(value)
3294+
a\b b0 b1
3295+
a0 0 1
3296+
a1 2 3
3297+
a\b b0 b1
3298+
a0 0 1
3299+
a1 2 3
3300+
3301+
One can also access elements of the value sequence directly, instead of iterating over it. Say we want to
3302+
retrieve the first and last values of our array, we could write:
3303+
3304+
>>> values = arr.values()
3305+
>>> values[0]
3306+
0
3307+
>>> values[-1]
3308+
3
3309+
"""
3310+
if axes is None:
3311+
combined = np.ravel(self.data)
3312+
# combined[::-1] *is* indexable
3313+
return combined if ascending else combined[::-1]
3314+
3315+
if not isinstance(axes, (tuple, AxisCollection)):
3316+
axes = (axes,)
3317+
3318+
def get_axis(a):
3319+
if isinstance(a, basestring):
3320+
return Axis(a) if '=' in a else self.axes[a]
3321+
elif isinstance(a, int):
3322+
return self.axes[a]
3323+
else:
3324+
assert isinstance(a, Axis)
3325+
return a
3326+
axes = [get_axis(a) for a in axes]
3327+
array = self.expand(axes, readonly=True) if expand else self
3328+
axes = array.axes[axes]
3329+
# move axes in front
3330+
transposed = array.transpose(axes)
3331+
# combine axes if necessary
3332+
combined = transposed.combine_axes(axes, wildcard=True) if len(axes) > 1 else transposed
3333+
# trailing .i is to support the case where axis < self.axes (ie the elements of the result are arrays)
3334+
return combined.i if ascending else combined.i[::-1].i
3335+
3336+
# TODO: we currently return a tuple of groups even for 1D arrays, which can be both a bad or a good thing.
3337+
# if we returned an NDGroup in all cases, it would solve the problem
3338+
# TODO: implement expand=True
3339+
def items(self, axes=None, ascending=True):
3340+
r"""Returns a (label, value) view of the array along axes.
3341+
3342+
Parameters
3343+
----------
3344+
axes : int, str or Axis or tuple of them, optional
3345+
Axis or axes along which to iterate and in which order. Defaults to None (all axes in the order they are
3346+
in the array).
3347+
ascending : bool, optional
3348+
Whether or not to iterate the axes in ascending order (from start to end). Defaults to True.
3349+
3350+
Returns
3351+
-------
3352+
Sequence
3353+
An object you can iterate (loop) on and index by position to get the Nth (label, value) couple along axes.
3354+
3355+
Examples
3356+
--------
3357+
First, define a small helper function to make the following examples more readable.
3358+
3359+
>>> def str_key(key):
3360+
... return tuple(str(k) for k in key)
3361+
3362+
Then create a test array:
3363+
3364+
>>> arr = ndtest((2, 2))
3365+
>>> arr
3366+
a\b b0 b1
3367+
a0 0 1
3368+
a1 2 3
3369+
3370+
By default it iterates on all axes, in the order they are in the array.
3371+
3372+
>>> for key, value in arr.items():
3373+
... print(str_key(key), "->", value)
3374+
('a0', 'b0') -> 0
3375+
('a0', 'b1') -> 1
3376+
('a1', 'b0') -> 2
3377+
('a1', 'b1') -> 3
3378+
>>> for key, value in arr.items(ascending=False):
3379+
... print(str_key(key), "->", value)
3380+
('a1', 'b1') -> 3
3381+
('a1', 'b0') -> 2
3382+
('a0', 'b1') -> 1
3383+
('a0', 'b0') -> 0
3384+
3385+
but you can specify another axis order:
3386+
3387+
>>> for key, value in arr.items(('b', 'a')):
3388+
... print(str_key(key), "->", value)
3389+
('b0', 'a0') -> 0
3390+
('b0', 'a1') -> 2
3391+
('b1', 'a0') -> 1
3392+
('b1', 'a1') -> 3
3393+
3394+
When you specify less axes than the array has, you get arrays back:
3395+
3396+
>>> # iterate on the "b" axis, that is return the (sub)array for each label along the "b" axis
3397+
... for key, value in arr.items('b'):
3398+
... print(str_key(key), value, sep="\n")
3399+
('b0',)
3400+
a a0 a1
3401+
0 2
3402+
('b1',)
3403+
a a0 a1
3404+
1 3
3405+
3406+
One can also access elements of the items sequence directly, instead of iterating over it. Say we want to
3407+
retrieve the first and last key-value pairs of our array, we could write:
3408+
3409+
>>> items = arr.items()
3410+
>>> first_key, first_value = items[0]
3411+
>>> str_key(first_key)
3412+
('a0', 'b0')
3413+
>>> first_value
3414+
0
3415+
>>> last_key, last_value = items[-1]
3416+
>>> str_key(last_key)
3417+
('a1', 'b1')
3418+
>>> last_value
3419+
3
3420+
"""
3421+
return SequenceZip((self.keys(axes, ascending=ascending), self.values(axes, ascending=ascending)))
3422+
31443423
def copy(self):
31453424
"""Returns a copy of the array.
31463425
"""
@@ -6713,6 +6992,7 @@ def __array__(self, dtype=None):
67136992

67146993
__array_priority__ = 100
67156994

6995+
# TODO: this should be a thin wrapper around a method in AxisCollection
67166996
def set_labels(self, axis=None, labels=None, inplace=False, **kwargs):
67176997
r"""Replaces the labels of an axis of array.
67186998

0 commit comments

Comments
 (0)