[英]Elegant min/max absolute values in java
在应用绝对值转换后,我需要在浮点值集合中获取最小值和最大值。 在python我会这样做
min(map(abs, [-5, -7, 10, 2]))
如何以最优雅的方式在java中执行相同的操作?
这是另一种方法。 这种方法不需要创建数组的第二个副本,因为Arrays.asList
只生成给定数组的数组支持视图 。 另一个潜在的优点是保留了最小值和最大值的符号。 在下面的示例中,最小值显示为1.333,最大值显示为-9.43。
它比Stefan的解决方案更复杂,但根据具体情况,它可能适合您。
Float numbers[] = {-9.43f, 2.3f, -8.2f, 1.333f};
// Calculate the minimum
Float min = Collections.min(Arrays.asList(numbers),
new Comparator<Float>() {
public int compare(Float o1, Float o2) {
Float result = Math.abs(o1) - Math.abs(o2);
return result > 0 ? 1 : result < 0 ? -1 : 0;
}
}
);
// Calculate the maximum
Float max = Collections.min(Arrays.asList(numbers),
new Comparator<Float>() {
public int compare(Float o1, Float o2) {
Float result = Math.abs(o2) - Math.abs(o1);
return result > 0 ? 1 : result < 0 ? -1 : 0;
}
}
);
System.out.println("Min = " + min);
System.out.println("Max = " + max);
输出:
Min = 1.333
Max = -9.43
编辑:为了回应评论中的“hatchetman82”,我决定运行一个简单的基准测试,看看我的解决方案与Stefan Kendall的比较。 对于少于一万个元素的小阵列,这两种解决方案几乎完全相同。 但是,对于较大的阵列,我的解决方案通常会表现更好。
Stefan的方法完全有效,但它使用的内存大约是我的两倍,因为它必须创建原始数组的副本才能存储每个元素的绝对值。 至于时间复杂度,我发现我的方法执行速度提高了4到7倍,主要是因为Stefan的方法需要复制数组。 请记住,这些基准测试是在一台机器(MacBook Pro,4GB,Core2 Duo @ 2.53)上执行的,结果将根据您的计算机和JVM的配置而有所不同。
Stefan的方法肯定更直接,在某些情况下我的表现更好。 所以基本上每个解决方案都是有效的,但根据具体情况,一个或另一个可能更好。
在“疯狂的东西”类别中:
import java.util.*;
import org.apache.commons.collections.iterators.IteratorEnumeration;
import org.apache.commons.functor.core.collection.TransformedIterator;
import org.apache.commons.functor.UnaryFunction;
//...
int commonsMin = Collections.min(
Collections.list((Enumeration<Integer>)
new IteratorEnumeration(
new TransformedIterator<Integer, Integer>(
Arrays.asList(3, -5, -7, 10, -2, 4).iterator(), new UnaryFunction<Integer, Integer>(){
public Integer evaluate(Integer a)
{
return Math.abs(a);
}
}))));
//...
如果其中一个Collections.min重载使用了Iterator,或者有一种简单的方法将Iterator转换为Collection,那么这真的不会那么疯狂。 Java 7闭包可能会更加明智。
编辑:这与番石榴 /谷歌收藏更干净。 我使用HashSet因为我们真的不关心顺序:
import com.google.common.base.Function;
import com.google.common.collect.Iterables;
import com.google.common.collect.Sets;
// ...
int guavaMin = Collections.min(
Sets.newHashSet(
Iterables.transform(
Sets.newHashSet(3, -5, -7, 10, -2, 4), new Function<Integer, Integer>(){
public Integer apply(Integer a)
{
return Math.abs(a);
}
})));
// ...
创建另一个(更实用的)答案,分开两种方法(参见Kevin Day的评论):
这可以在一个数组传递中完成(排序为O(log n)),而不创建任何新列表。 只是不要使用Collections.max。 相反,只需计算出绝对值并具有最小/最大运行:
List<Integer> l = Arrays.asList(3, -5, -7, 10, -2, 4);
int iterMin = Integer.MAX_VALUE;
for(Integer i : l)
if(Math.abs(i) < iterMin)
iterMin = Math.abs(i);
如果要保留原始值,可以轻松地执行此操作:
int iterMinOrig = Integer.MAX_VALUE;
for(Integer i : l)
if(Math.abs(i) < Math.abs(iterMinOrig))
iterMinOrig = i;
我建议使用比较器。 例如,如果您的列表是双打,那么您有以下选项:
获得最大绝对值:
double maxAbs = Collections.max( myList, new Comparator<Double>() {
@Override
public int compare(Double x, Double y) {
return Math.abs(x) < Math.abs(y) ? -1 : 1;
}
});
获得最小绝对值:
double minAbs = Collections.max( myList, new Comparator<Double>() {
@Override
public int compare(Double x, Double y) {
return Math.abs(x) > Math.abs(y) ? -1 : 1;
}
});
按升序对列表进行排序(相对于绝对值):
Collections.sort( myList, new Comparator<Double>() {
@Override
public int compare(Double x, Double y) {
return Math.abs(x) < Math.abs(y) ? -1 : 1;
}
});
按降序对列表进行排序(相对于绝对值):
Collections.sort( myList, new Comparator<Double>() {
@Override
public int compare(Double x, Double y) {
return Math.abs(x) > Math.abs(y) ? -1 : 1;
}
});
如果你有其他类型的整数,只需用整数替换Double
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.