使用Linq进行搜索

4
我有一个对象集合,每个对象都有一个整数Frame属性。给定一个整数,我想找到集合中最接近该整数的Frame属性所对应的对象。
目前我的做法是:
public static void Search(int frameNumber)
{
    var differences = (from rec in _records
                       select new { FrameDiff = Math.Abs(rec.Frame - frameNumber), Record = rec }).OrderBy(x => x.FrameDiff);

    var closestRecord = differences.FirstOrDefault().Record;

    //continue work...
}

这很不错,但我的收藏中有200,000个项目,并且我经常调用此方法。是否有一种相对简单、更有效的方法来完成这个任务?


1
这只是LINQ到对象集合还是LINQ到SQL? - Jimmy
我有一个对象的集合。 - jsmith
5个回答

5
var closestRecord = _records.MinBy(rec => Math.Abs(rec.Frame - frameNumber));

使用来自MoreLINQ的MinBy。


3

您可能想尝试的是将帧存储在一个按Frame排序的数据结构中。然后,当您需要找到最接近给定帧数的帧时,可以进行二进制搜索。


也许可以考虑使用 SortedList 集合作为数据结构。 - Reddog
难道不是要用linq来做吗?这怎么用linq实现?有代码示例吗? - jsmith
我可以接受不使用linq的解决方案。我只是想要“简单”的东西。 - Phil

1

我不确定我会用LINQ来做这件事,至少不会加一个orderby。

static Record FindClosestRecord(IEnumerable<Record> records, int number)
{
    Record closest = null;
    int leastDifference = int.MaxValue;

    foreach (Record record in records)
    {
        int difference = Math.Abs(number - record.Frame);
        if (difference == 0)
        {
            return record; // exact match, return early
        }
        else if (difference < leastDifference)
        {
            leastDifference = difference;
            closest = record;
        }
    }

    return closest;
}

这基本上就是 MoreLINQ 的 MinBy 方法的工作方式,正如 dtb 的答案所建议的那样。(尽管 MinBy 无法为精确匹配特别处理早期退出。) - LukeH
如果你有一个已排序的集合,你可以有一个更好的早期退出。此外,如果你使用一个“for”循环,你可以记住上次使用的索引,并从那里开始搜索,而不是从集合的开头开始。简单和快速之间的良好平衡。这就是我最终选择做的事情,效果很好。 - Phil

0

你可以将语句合并成一个,例如:

var closestRecord = (from rec in _records
                   select new { FrameDiff = Math.Abs(rec.Frame - frameNumber), 
                   Record = rec }).OrderBy(x => x.FrameDiff).FirstOrDefault().Record;

2
我认为他的问题是排序(实际上不需要)花费了很长时间。 - Ghostrider

0
也许你可以将大的项目列表分成5-10个较小的列表,按照它们的Framediff或其他方式排序?
这样,如果你知道需要搜索哪个列表,搜索会更快。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接