Java Lambda-找到包含向量3D实例的三角形极值的更好方法

Java Lambda-找到包含向量3D实例的三角形极值的更好方法,java,vector,lambda,compare,java-stream,Java,Vector,Lambda,Compare,Java Stream,三角形多边形有一个数组顶点包含3个矢量3D实例。方法应该找到三角形的轴(x、y或z)上的极值(最小值/最大值) 例如,三角形A(0,0,3)B(1,2,3)C(2,2,-4)在z轴上的最小值为-4 当前的实现如下所示: public class Triangle implements Iterable<Vector3D> { private final Vector3D[] vertices; private final double kEpsi

三角形多边形有一个数组
顶点
包含3个
矢量3D
实例。方法应该找到三角形的轴(x、y或z)上的极值(最小值/最大值)

例如,三角形
A(0,0,3)B(1,2,3)C(2,2,-4)
在z轴上的最小值为
-4

当前的实现如下所示:

   public class Triangle implements Iterable<Vector3D> {
        private final Vector3D[] vertices;
        private final double kEpsilon = 1e-8;

        public Triangle(Vector3D... vertices) {
            Preconditions.checkArgument(vertices.length == 3);
            this.vertices = vertices;
        }

        public double getExtremeValueForAxis(int axis) {
            var minimum = getValueByAxisIndex(Arrays.stream(vertices).min((v, vOther) -> {
                var vValueOnAxis = getValueByAxisIndex(v, axis);
                var vOtherValueOnAxis = getValueByAxisIndex(vOther, axis);
                return Double.compare(vValueOnAxis, vOtherValueOnAxis);
            }).get(), axis);
            return minimum;
        }

        private static double getValueByAxisIndex(final Vector3D vertex, final int axis) {
            switch(axis) {
                case 0: return vertex.getX();
                case 1: return vertex.getY();
                case 2: return vertex.getZ();
                default: throw new IllegalArgumentException("Axis needs to be in 3D space!");
            }
        }
  }
public类实现了Iterable{
私有最终矢量3D[]顶点;
私人最终双kEpsilon=1e-8;
公共三角形(矢量3D…顶点){
先决条件.checkArgument(顶点.length==3);
这个。顶点=顶点;
}
公共双getExtremeValueForAxis(int轴){
var最小值=getValueByAxisIndex(Arrays.stream(顶点).min((v,vOther)->{
var vValueOnAxis=getValueByAxisIndex(v,轴);
var vOtherValueOnAxis=getValueByAxisIndex(vOther,axis);
返回Double.compare(vValueOnAxis,vOtherValueOnAxis);
}).get(),轴);
返回最小值;
}
私有静态双getValueByAxisIndex(最终矢量3D顶点,最终整数轴){
开关(轴){
案例0:返回vertex.getX();
案例1:返回vertex.getY();
案例2:返回vertex.getZ();
默认值:抛出新的IllegalArgumentException(“轴需要在三维空间中!”);
}
}
}

我如何让用户通过传递函数
可选的min(Comparator来搜索最小值/最大值?我想先使用将流中的项目映射到
int
,然后使用该方法来获取最小值。该方法不需要参数,因为它与整数一起工作,直接比较整数

int minX = Arrays.stream(vertices).mapToInt(Vector3D::getX).min().getAsInt();
int minY = Arrays.stream(vertices).mapToInt(Vector3D::getY).min().getAsInt();
int minZ = Arrays.stream(vertices).mapToInt(Vector3D::getZ).min().getAsInt();

int min =  Arrays.asList(minX, minY, minZ).stream().mapToInt(i -> i).min().getAsInt();
或者,将所有值连接到一个列表中,并对其执行流操作:

List<Integer> integers = new ArrayList<>();
Arrays.stream(vertices).forEach(i -> { 
    integers.add(i.getX()); integers.add(i.getY()); integers.add(i.getZ());
});
int min = integers.stream().mapToInt(i -> i).min().getAsInt();
List integers=new ArrayList();
数组.stream(顶点).forEach(i->{
integers.add(i.getX());integers.add(i.getY());integers.add(i.getZ());
});
int min=integers.stream().mapToInt(i->i.min().getAsInt();

通过让调用方使用函数选择比较器(本例中为减速机)和轴,函数及其调用可以真正简化:

/** valueFunction selects the axis 
    reducer selects which of 2 values to retain (max/min in this case)*/
public double getExtremeValueForAxis(
   Function<Vector3D, Double> valueFunction, BinaryOperator<Double> reducer) {
     return Arrays.stream(vertices)
              .map(valueFunction)
              .reduce(reducer)
              .get();
}
当然,也可以使用lambda表达式提供内联约简器和映射器:

new Triangle().getExtremeValueForAxis(v -> v.getY(), 
            (n1, n2) -> n1 > n2 ? n2 : n1); //min by axis 0

我已经用
mapToDouble
getAsDouble
而不是
mapToInt
getAsInt()
对它进行了测试。但是这仍然不能解决我需要在方法
getExtremeValueForAxis
中使用函数参数的问题,因此在调用函数时可以指定是否要调用
.min()
.max()
.avg()
etc…不写3个或更多的方法。我无法想象你预期的比较结果。你能起草一份方法调用的近似结果吗?帮助-看看欧内斯特·基维尔提供的答案,这将给你一张我希望解决方案如何工作的图片。我现在就得到了它。:))使用lambda表达式,如
(n1,n2)->n1>n2?不建议使用n2:n1
,因为它没有关于NaN值的明确政策。相比之下,
Math::min
有一个关于NaN的成文政策;如果任何值为NaN,结果将为NaN,因此您可以发现任何错误。
new Triangle().getExtremeValueForAxis(v -> v.getY(), 
            (n1, n2) -> n1 > n2 ? n2 : n1); //min by axis 0