Skip to content

Commit

Permalink
Add split_indices
Browse files Browse the repository at this point in the history
Adds a utility function, `split_indices`, for splitting up slices with
multiple indices into a list of slices each with a single index. This is
handy when working with libraries that accept slices that have a single
index, but balk when multiple indices are provided. In these cases, one
can split up the multiple indices into multiple slices, which can then
be iterated over. Construction of the total result is up to user.
  • Loading branch information
jakirkham committed Feb 17, 2017
1 parent d6246cd commit 88ea2e2
Show file tree
Hide file tree
Showing 2 changed files with 90 additions and 0 deletions.
61 changes: 61 additions & 0 deletions kenjutsu/format.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@


import collections
import itertools
import numbers


Expand Down Expand Up @@ -292,3 +293,63 @@ def reformat_slices(slices, lengths=None):
)

return(new_slices)


def split_indices(slices):
"""
Splits slices with multiple indices into multiple splices.
Support of slices with a sequence of indices is varied. Some
libraries like NumPy support them without issues. Other libraries
like h5py support them as long as they are in sequential order.
In still other libraries support is non-existent. However, in
all those cases normally a single index is permissible. This
converts slices with multiple indices into a list of slices with
a single index each. While this still leaves it up to the user
to iterate over these and combine the results in some sensible
way, it is better than just getting a failure and should extend
well to a variety of cases.
Args:
slices(tuple(slice)): a tuple of slices to split
Returns:
(list(tuple(slice))): a list of a tuple of slices
Examples:
>>> split_indices(
... (
... 3,
... Ellipsis,
... [0, 1, 2],
... slice(2, 5),
... slice(4, 6, 2)
... )
... ) # doctest: +NORMALIZE_WHITESPACE
[(3, Ellipsis, slice(0, 1, 1), slice(2, 5, 1), slice(4, 6, 2)),
(3, Ellipsis, slice(1, 2, 1), slice(2, 5, 1), slice(4, 6, 2)),
(3, Ellipsis, slice(2, 3, 1), slice(2, 5, 1), slice(4, 6, 2))]
"""

ref_slices = reformat_slices(slices)

mtx_slices = []
for each_dim_slice in ref_slices:
if each_dim_slice is Ellipsis:
mtx_slices.append([each_dim_slice])
elif isinstance(each_dim_slice, numbers.Integral):
mtx_slices.append([each_dim_slice])
elif isinstance(each_dim_slice, slice):
mtx_slices.append([each_dim_slice])
elif isinstance(each_dim_slice, collections.Sequence):
new_slice = []
for i in each_dim_slice:
new_slice.append(index_to_slice(i))
mtx_slices.append(new_slice)

result_slices = []
for each_dim_slice in itertools.product(*mtx_slices):
result_slices.append(tuple(each_dim_slice))

return result_slices
29 changes: 29 additions & 0 deletions tests/test_format.py
Original file line number Diff line number Diff line change
Expand Up @@ -482,3 +482,32 @@ def test_reformat_slices(self):
slice(0, 1, 1)
)
)

def test_split_indices(self):
with self.assertRaises(ValueError) as e:
format.split_indices(
([0, 1], [0, 1]),
)

self.assertEqual(
str(e.exception),
"Only one integral sequence supported. Instead got `2`."
)

sp_slice = format.split_indices(
(
3,
Ellipsis,
[0, 1, 2],
slice(2, 5),
slice(4, 6, 2)
)
)
self.assertEqual(
sp_slice,
[
(3, Ellipsis, slice(0, 1, 1), slice(2, 5, 1), slice(4, 6, 2)),
(3, Ellipsis, slice(1, 2, 1), slice(2, 5, 1), slice(4, 6, 2)),
(3, Ellipsis, slice(2, 3, 1), slice(2, 5, 1), slice(4, 6, 2))
]
)

0 comments on commit 88ea2e2

Please sign in to comment.