如何找到最接近任意(非成员)数字的数组元素?

时间:2010-11-16 11:39:52

标签: c# search approximate

看似相似的问题:“Finding closest number in an array”(在Java中)和“find nearest match to array of doubles”(实际上是地理问题)。

我有一个(排序的)双打数组。给定一个任意数字(可能与其中一个数组元素完全匹配),如何返回最接近匹配的数字索引?

例如,使用以下数组:

  • 1.8
  • 2.4
  • 2.7
  • 3.1
  • 4.5

查询2.5将返回索引为1,对应于2.4的值。

用于检测完全位于数组元素范围之外的值的加值点。例如,使用上面列出的数组,您的代码可能会决定4.6是否在,但5.9已经完成。如果您想尝试这部分问题,具体内容掌握在您手中。

5 个答案:

答案 0 :(得分:11)

Array.BinarySearch,返回:

  

指定数组中指定值的索引(如果找到值)。如果未找到值且值小于数组中的一个或多个元素,则为负数,它是第一个元素的索引的按位补码,其大于值。如果找不到值并且value大于数组中的任何元素,则为负数,它是(最后一个元素的索引加1)的按位补码。

现在这不会让你100%的方式,因为你会知道这个数字小于或大于匹配,但它实际上只留下两个指数来检查。

答案 1 :(得分:6)

使用LINQ执行此操作的一种方法是:

public int GetClosestIndex( List<double> doublelist, double targetvalue )
{
  return doublelist.IndexOf(doublelist.OrderBy(d => Math.Abs(d - targetvalue)).ElementAt(0));
}

它可能有一些性能问题,但如果列表不长,则不应该出现问题。此外,如果两个元素与目标值相等,它将返回那些元素的第一个索引。

答案 2 :(得分:3)

也许不是最快的解决方案,但肯定是令人愉快的眼睛:

double search;
double[] array;

var nearest = (
    from value in array
    orderby Math.Abs(value - search)
    select value).First();

var index = array.IndexOf(nearest);

请注意,这绝对比二进制搜索算法慢,因为它需要处理数组中的每个元素,并且排序意味着构建这些项的哈希表。

答案 3 :(得分:0)

这样的事情:

double[] values = new double[]
{
    1.8,
    2.4,
    2.7,
    3.1,
    4.5
};

double difference = double.PositiveInfinity;
int index = -1;

double input = 2.5;

for (int i = 0; i < values.Length; i++)
{
    double currentDifference = Math.Abs(values[i] - input);

    if (currentDifference < difference)
    {
        difference = currentDifference;
        index = i;
    }

    // Stop searching when we've encountered a value larger
    // than the inpt because the values array is sorted.
    if (values[i] > input)
        break;
}

Console.WriteLine("Found index: {0} value {1}", index, values[index]);

答案 4 :(得分:0)

List<int> results;
int target = 0;
int nearestValue = 0;
if (results.Any(ab => ab == target)) {
    nearestValue= results.FirstOrDefault<int>(i => i == target);
} else {
    int greaterThanTarget = 0;
    int lessThanTarget = 0;
    if (results.Any(ab => ab > target) {
        greaterThanTarget = results.Where<int>(i => i > target).Min();
    }

    if (results.Any(ab => ab < target)) {
        lessThanTarget = results.Where<int>(i => i < target).Max();
    }

    if (lessThanTarget == 0 ) {
        nearestValue= greaterThanTarget;
    } else if (greaterThanTarget == 0) {
        nearestValue = lessThanTarget;
    } else {
        if (target - lessThanTarget < greaterThanTarget - target) {
            nearestValue = lessThanTarget;
        } else {
            nearestValue = greaterThanTarget;
        }
    }
}