在应用绝对值转换后,我需要在浮点值集合中获取最小值和最大值。在python中我会这样做
min(map(abs, [-5, -7, 10, 2]))
如何以最优雅的方式在java中执行相同的操作?
答案 0 :(得分:4)
你可能会做一些疯狂的事情,但最直接的解决方案是:
List<Integer> x = new ArrayList<Integer>(Arrays.asList( {-5,-7,10,2} } );
for( int i = 0; i < x.size(); i++ ){
x.set( i, Math.abs(x.get(i)) );
}
return Collections.max( x );
Collections和Arrays无限有用。
答案 1 :(得分:3)
这是另一种方法。此方法不需要创建数组的第二个副本,因为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的配置而有所不同。
斯特凡的方法肯定更直接,在某些情况下我的表现更好。所以基本上每个解决方案都是有效的,但根据具体情况,其中一个或另一个可能更好。
答案 2 :(得分:2)
在“疯狂的东西”类别中:
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 closures可能会更加明智。
编辑:使用Guava / Google Collections时更干净。我使用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);
}
})));
// ...
答案 3 :(得分:1)
创建另一个(更实用的)答案,分开两种方法(参见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;
答案 4 :(得分:0)
我建议使用比较器。例如,如果您的列表是双打的,那么您有以下选项:
获取最大绝对值:
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 替换为 Integer
答案 5 :(得分:0)
简短(优雅?):
int min = Arrays.stream(array).map(Math::abs).min().getAsInt();
int max = Arrays.stream(array).map(Math::abs).max().getAsInt();
或者,为了避免遍历两次(更有效但可能稍微不那么优雅):
IntSummaryStatistics d = Arrays.stream(array).map(Math::abs).summaryStatistics();
int min = d.getMin();
int max = d.getMax();