我想知道如何编写一个简单的java方法,将closet Integer发现到已排序的Integer列表中的给定值。
这是我的第一次尝试:
public class Closest {
private static List<Integer> integers = new ArrayList<Integer>();
static {
for (int i = 0; i <= 10; i++) {
integers.add(Integer.valueOf(i * 10));
}
}
public static void main(String[] args) {
Integer closest = null;
Integer arg = Integer.valueOf(args[0]);
int index = Collections.binarySearch(
integers, arg);
if (index < 0) /*arg doesn't exist in integers*/ {
index = -index - 1;
if (index == integers.size()) {
closest = integers.get(index - 1);
} else if (index == 0) {
closest = integers.get(0);
} else {
int previousDate = integers.get(index - 1);
int nextDate = integers.get(index);
if (arg - previousDate < nextDate - arg) {
closest = previousDate;
} else {
closest = nextDate;
}
}
} else /*arg exists in integers*/ {
closest = integers.get(index);
}
System.out.println("The closest Integer to " + arg + " in " + integers
+ " is " + closest);
}
}
您对此解决方案有何看法?我相信有一种更清洁的方式来完成这项工作......
也许这样的方法存在于Java库的某个地方,我错过了它?
Manu
答案 0 :(得分:32)
试试这个小方法:
public int closest(int of, List<Integer> in) {
int min = Integer.MAX_VALUE;
int closest = of;
for (int v : in) {
final int diff = Math.abs(v - of);
if (diff < min) {
min = diff;
closest = v;
}
}
return closest;
}
一些测试用例:
private final static List<Integer> list = Arrays.asList(10, 20, 30, 40, 50);
@Test
public void closestOf21() {
assertThat(closest(21, list), is(20));
}
@Test
public void closestOf19() {
assertThat(closest(19, list), is(20));
}
@Test
public void closestOf20() {
assertThat(closest(20, list), is(20));
}
答案 1 :(得分:10)
科特琳很有帮助
fun List<Int>.closestValue(value: Int) = minBy { abs(value - it) }
val values = listOf(1, 8, 4, -6)
println(values.closestValue(-7)) // -6
println(values.closestValue(2)) // 1
println(values.closestValue(7)) // 8
列表无需进行顺便说一句
答案 2 :(得分:1)
我认为你所拥有的是最简单,最有效的方法。在排序列表中查找“最接近”的项目并不是编程中常见的内容(通常会查找较大的项目或较小的项目)。这个问题只对数字类型有意义,所以不是很普遍,因此有一个库函数是不常见的。
答案 3 :(得分:1)
为了解决这个问题,我用distanceTo方法扩展了Comparable Interface。 distanceTo的实现返回一个表示预期距离的double值,它与compareTo实现的结果兼容。
以下示例仅使用苹果来说明这个想法。您可以按重量,体积或甜度交换直径。袋子将始终返回“最接近的”苹果(最大的类似,怀疑或味道)
public interface ExtComparable<T> extends Comparable<T> {
public double distanceTo(T other);
}
public class Apple implements Comparable<Apple> {
private Double diameter;
public Apple(double diameter) {
this.diameter = diameter;
}
public double distanceTo(Apple o) {
return diameter - o.diameter;
}
public int compareTo(Apple o) {
return (int) Math.signum(distanceTo(o));
}
}
public class AppleBag {
private List<Apple> bag = new ArrayList<Apple>();
public addApples(Apple...apples){
bag.addAll(Arrays.asList(apples));
Collections.sort(bag);
}
public removeApples(Apple...apples){
bag.removeAll(Arrays.asList(apples));
}
public Apple getClosest(Apple apple) {
Apple closest = null;
boolean appleIsInBag = bag.contains(apple);
if (!appleIsInBag) {
bag.addApples(apple);
}
int appleIndex = bag.indexOf(apple);
if (appleIndex = 0) {
closest = bag.get(1);
} else if(appleIndex = bag.size()-1) {
closest = bag.get(bag.size()-2);
} else {
double absDistToPrev = Math.abs(apple.distanceTo(bag.get(appleIndex-1));
double absDistToNext = Math.abs(apple.distanceTo(bag.get(appleIndex+1));
closest = bag.get(absDistToNext < absDistToPrev ? next : previous);
}
if (!appleIsInBag) {
bag.removeApples(apple);
}
return closest;
}
}
答案 4 :(得分:1)
没有二进制搜索的解决方案(利用列表进行排序):
public int closest(int value, int[] sorted) {
if(value < sorted[0])
return sorted[0];
int i = 1;
for( ; i < sorted.length && value > sorted[i] ; i++);
if(i >= sorted.length)
return sorted[sorted.length - 1];
return Math.abs(value - sorted[i]) < Math.abs(value - sorted[i-1]) ?
sorted[i] : sorted[i-1];
}
答案 5 :(得分:0)
当然,你可以简单地使用for循环遍历并跟踪你所在的值和值之间的差异。它会看起来更干净,但要慢得多。
答案 6 :(得分:0)
未经测试
int[] randomArray; // your array you want to find the closest
int theValue; // value the closest should be near to
for (int i = 0; i < randomArray.length; i++) {
int compareValue = randomArray[i];
randomArray[i] -= theValue;
}
int indexOfClosest = 0;
for (int i = 1; i < randomArray.length; i++) {
int compareValue = randomArray[i];
if(Math.abs(randomArray[indexOfClosest] > Math.abs(randomArray[i]){
indexOfClosest = i;
}
}
答案 7 :(得分:0)
我认为你的回答可能是返回单一结果的最有效方法。
但是,您的方法存在的问题是0(如果没有列表),1或2个可能的解决方案。当你有一个功能的两个可能的解决方案,你的问题真的开始:如果这不是最终的答案,但只是在一系列步骤中的第一个确定最佳的行动方案,以及你没有的答案怎么办?返回会提供更好的解决方案吗?唯一正确的做法是考虑两个答案并仅在最后比较进一步处理的结果。
将平方根函数看作是一个类似的问题。
答案 8 :(得分:0)
如果你没有大量关注性能(假设该组被搜索了两次),我认为使用Navigable设置可以获得更清晰的代码:
public class Closest
{
private static NavigableSet<Integer> integers = new TreeSet<Integer>();
static
{
for (int i = 0; i <= 10; i++)
{
integers.add(Integer.valueOf(i * 10));
}
}
public static void main(String[] args)
{
final Integer arg = Integer.valueOf(args[0]);
final Integer lower = integers.lower(arg);
final Integer higher = integers.higher(arg);
final Integer closest;
if (lower != null)
{
if (higher != null)
closest = (higher - arg > arg - lower) ? lower : higher;
else
closest = lower;
}
else
closest = higher;
System.out.println("The closest Integer to " + arg + " in " + integers + " is " + closest);
}
}
答案 9 :(得分:0)
您的解决方案似乎渐近最优。如果它使用Math.min / max,它可能会稍微快一点(尽管可能不太可维护)。一个好的JIT可能具有使这些变得快速的内在函数。
int index = Collections.binarySearch(integers, arg);
if (index < 0) {
int previousDate = integers.get(Math.max(0, -index - 2));
int nextDate = integers.get(Math.min(integers.size() - 1, -index - 1));
closest = arg - previousDate < nextDate - arg ? previousDate : nextDate;
} else {
closest = integers.get(index);
}
答案 10 :(得分:0)
可能有点晚了,但这会起作用,这是一个数据结构二进制搜索:
科特林:
fun binarySearch(list: List<Int>, valueToCompare: Int): Int {
var central: Int
var initialPosition = 0
var lastPosition: Int
var centralValue: Int
lastPosition = list.size - 1
while (initialPosition <= lastPosition) {
central = (initialPosition + lastPosition) / 2 //Central index
centralValue = list[central] //Central index value
when {
valueToCompare == centralValue -> {
return centralValue //found; returns position
}
valueToCompare < centralValue -> {
lastPosition = central - 1 //position changes to the previous index
}
else -> {
initialPosition = central + 1 //position changes to next index
}
}
}
return -1 //element not found
}
Java:
public int binarySearch(int list[], int valueToCompare) {
int central;
int centralValue;
int initialPosition = 0;
int lastPosition = list . length -1;
while (initialPosition <= lastPosition) {
central = (initialPosition + lastPosition) / 2; //central index
centralValue = list[central]; //central index value
if (valueToCompare == centralValue) {
return centralValue; //element found; returns position
} else if (valueToCompare < centralValue) {
lastPosition = central - 1; //Position changes to the previous index
} else {
initialPosition = central + 1; //Position changes to the next index
}
return -1; //element not found
}
}
我希望这会有所帮助,祝您编码愉快。