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