diff --git a/polytope_feature/datacube/transformations/datacube_cyclic/datacube_cyclic.py b/polytope_feature/datacube/transformations/datacube_cyclic/datacube_cyclic.py index b7e402eae..3373dd082 100644 --- a/polytope_feature/datacube/transformations/datacube_cyclic/datacube_cyclic.py +++ b/polytope_feature/datacube/transformations/datacube_cyclic/datacube_cyclic.py @@ -1,7 +1,7 @@ import math from copy import deepcopy -from ....utility.combinatorics import unique +from ....utility.list_tools import unique from ..datacube_transformations import DatacubeAxisTransformation diff --git a/polytope_feature/engine/hullslicer.py b/polytope_feature/engine/hullslicer.py index 8d3df84a2..9a99682a6 100644 --- a/polytope_feature/engine/hullslicer.py +++ b/polytope_feature/engine/hullslicer.py @@ -9,9 +9,10 @@ from ..datacube.datacube_axis import UnsliceableDatacubeAxis from ..datacube.tensor_index_tree import TensorIndexTree from ..shapes import ConvexPolytope -from ..utility.combinatorics import argmax, argmin, group, tensor_product, unique +from ..utility.combinatorics import group, tensor_product from ..utility.exceptions import UnsliceableShapeError from ..utility.geometry import lerp +from ..utility.list_tools import argmax, argmin, unique from .engine import Engine diff --git a/polytope_feature/shapes.py b/polytope_feature/shapes.py index 70ad66b33..e05347b4e 100644 --- a/polytope_feature/shapes.py +++ b/polytope_feature/shapes.py @@ -5,6 +5,8 @@ import tripy +from .utility.list_tools import unique + """ Shapes used for the constructive geometry API of Polytope """ @@ -60,11 +62,11 @@ def polytope(self): # This is the only shape which can slice on axes without a discretizer or interpolator class Select(Shape): - """Matches several discrete value""" + """Matches several discrete values""" def __init__(self, axis, values, method=None): self.axis = axis - self.values = values + self.values = unique(values) self.method = method def axes(self): diff --git a/polytope_feature/utility/combinatorics.py b/polytope_feature/utility/combinatorics.py index 629ebbec8..4040c40db 100644 --- a/polytope_feature/utility/combinatorics.py +++ b/polytope_feature/utility/combinatorics.py @@ -46,19 +46,3 @@ def validate_axes(actual_axes, test_axes): raise AxisNotFoundError(ax) return True - - -def unique(points): - points.sort() - points = [k for k, _ in itertools.groupby(points)] - return points - - -def argmin(points): - amin = min(range(len(points)), key=points.__getitem__) - return amin - - -def argmax(points): - amax = max(range(len(points)), key=points.__getitem__) - return amax diff --git a/polytope_feature/utility/list_tools.py b/polytope_feature/utility/list_tools.py index 2d18917c1..51b8c7fec 100644 --- a/polytope_feature/utility/list_tools.py +++ b/polytope_feature/utility/list_tools.py @@ -1,3 +1,6 @@ +import itertools + + def bisect_left_cmp(arr, val, cmp): left = -1 r = len(arr) @@ -20,3 +23,19 @@ def bisect_right_cmp(arr, val, cmp): else: r = e return r + + +def unique(points): + points.sort() + points = [k for k, _ in itertools.groupby(points)] + return points + + +def argmin(points): + amin = min(range(len(points)), key=points.__getitem__) + return amin + + +def argmax(points): + amax = max(range(len(points)), key=points.__getitem__) + return amax diff --git a/tests/test_slicing_xarray_3D.py b/tests/test_slicing_xarray_3D.py index 06df3ec6b..72f68d0ff 100644 --- a/tests/test_slicing_xarray_3D.py +++ b/tests/test_slicing_xarray_3D.py @@ -249,3 +249,11 @@ def test_intersection_point_disk_polygon(self): result = self.API.retrieve(request) paths = [r.flatten().values() for r in result.leaves] assert ((pd.Timestamp("2000-01-01 00:00:00"),), (3,), (1,)) in paths + + def test_duplicate_values_select(self): + request = Request(Select("step", [3, 3]), Select("level", [1]), Select("date", ["2000-01-01"])) + result = self.API.retrieve(request) + result.pprint() + assert len(result.leaves) == 1 + path = result.leaves[0].flatten()["step"] + assert len(path) == 1