C#最快的搜索对象,其最近值为

时间:2017-06-05 12:14:11

标签: c# .net

我尝试在列表中找到一个具有最接近值的对象 我写了这个:

float target = 100.0f;
int index = int.MaxValue;
float nearest = float.MaxValue;
for(int i = 0; i < objectList.Count; i++)
{
   if(Math.Abs(objectList[i].value - target) < nearest)
   {
       nearest = Math.Abs(objectList[i].value - target);
       index = i;
   }
}

//do something with objectList[index]

这实际上有效,但是当列表太大时,它会耗费相当多的时间进行搜索。

我知道有可能这样做,但我不知道它是什么。

4 个答案:

答案 0 :(得分:2)

您可以通过缓存某些值并反转循环来略微加快速度:

$(modal).on('hide', window[close_function]() );

此外,如果您的对象列表没有太大变化,您可以排序并应用二进制最近搜索,它将在 O(log(n))中运行即可。可以做很多优化。

例如,您可以将所有内容放入已排序的二叉树(例如RB树)并对其进行搜索。它的运行速度比普通外观快得多。当然,只有在此列表中有大量搜索时,这才有效。

其他方法是将数组拆分成批处理并通过 Parallel.For 同时处理它们。然后只处理批次的结果。

答案 1 :(得分:1)

除非您的列表已排序,否则除了检查每个对象之外别无他法。您可以在变量中保存距离,这样您就不会计算两次。

float target = 100.0f;
int index = int.MaxValue;
float nearest = float.MaxValue;
for(int i = 0; i < objectList.Count; i++)
{
   float dist = Math.Abs(objectList[i].value - target);
   if(dist < nearest)
   {
       nearest = dist;
       index = i;
   }
}

答案 2 :(得分:0)

排序和搜索时间

对于没有受过正规教育的开发人员来说,这是非常困难的。 如果您的对象列表已经排序。您可以使用二进制搜索。 如果您首先需要对列表进行排序,那么您将不会节省时间,因为您的方法需要Θ(n log(n))时间并且排序需要Θ(n log(n))时间并且搜索排序列表需要Θ(log(n))时间,这比你的方法慢。

如果您的列表已经排序,例如使用sortedList,则为Buf。 在Θ(log(n))时间内可以使用二进制搜索来查找最近的项目。 (这是令人难以置信的快速)

大问题:二进制搜索会找到一个确切的项目,而不是最接近的项目。这意味着我们需要推出自己的实现。这是一个执行此操作的示例应用程序,函数public T findClosest是我们的二进制搜索实现。

使用二进制搜索(Visual Studio C#控制台应用程序)

查找最接近的值

您可以使用它来测试,玩游戏并了解有关递归结构的更多信息。

版权所有2017 Eldar Kersebaum

根据Apache许可证2.0版(&#34;许可证&#34;)获得许可;除非符合许可,否则您不得使用此文件。您可以在

获取许可证副本

http://www.apache.org/licenses/LICENSE-2.0 除非适用法律要求或书面同意,否则根据许可证分发的软件将按照“现状”分发。基础,不附带任何明示或暗示的担保或条件。有关管理许可下的权限和限制的特定语言,请参阅许可证。

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading.Tasks;


namespace FindingClosestObjectInList
{
    class exampleObject
    {
        public float value;
    }
    class Program
    {
        static void Main(string[] args)
        {
            //Generate objectList with some random value
            var objectList = new SortedList<float, exampleObject>();
            var rnd = new Random();
            for (int i = 0; i < 10000; i++)
            {
                var o = new exampleObject();
                o.value = (float)(rnd.NextDouble()); 
                //Values need to be Unique, that might be a problem for you.
                if (!objectList.Keys.Contains(o.value))
                {
                    objectList.Add(o.value, o);
                }
            }
            float target = .314f;
            var closestToTarget = objectList.Keys.FindClosest(target);
            Console.WriteLine(closestToTarget);
            Console.ReadKey();
        }
    }
    public static class ExtensionMethod
    {
        public static T FindClosest<T>(this IList<T> sortedCollection, T target) 
            where T : IComparable<T>, IConvertible
        {
            //Initialize borders for binary search
            int begin = 0;
            int end = sortedCollection.Count;
            T lastElement = target;

            while (end > begin)
            {
                int index = (begin + end) / 2;
                lastElement = sortedCollection[index];

                //Small change to binary search, to make sure we pick the closer one,
                //when we two values left.
                if (end - begin == 2)
                {
                    //Distanzes between the two values and the 
                    var a = sortedCollection[begin];
                    var b = sortedCollection[begin + 1];
                    var aDist = substractGeneric(a, target);
                    var bDist = substractGeneric(b, target);

                    return a.CompareTo(b) <= 0 ? a : b;
                }
                //Actual binary search
                if (lastElement.CompareTo(target) >= 0)
                    end = index;
                else
                    begin = index + 1;
            }
            //Normal ending of binary search.
            return lastElement;
        }
        //If your Type that doesn't support substraction, this will explode at RUNTIME.
        public static T substractGeneric<T>(T a, T b)
            where T : IConvertible  //Will make it more difficult to call this function with stupid Ts, but might still explode.
        {
            return (dynamic)a - (dynamic)b;
        }
    }
}

答案 3 :(得分:-1)

你可以像这样使用linq表达式:

 var  newList = objectList.Select(i => new { value = i, delta = Math.Abs(i - target) }).OrderByDescending(i=>i.delta);
    nearest = (newList.ToArray())[0].value;