2010-06-03 8 views
4

У меня есть коллекция объектов, каждая из которых имеет свойство int Frame. Учитывая int, я хочу найти объект в коллекции с ближайшим фреймом.Поиск с Linq

Вот что я делал до сих пор:

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 to SQL? – Jimmy

+0

«У меня есть коллекция объектов», первое предложение в вопросе. ;) – jsmith

ответ

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

используя MinBy от MoreLINQ.

3

Что вы можете попробовать, так это хранить фреймы в структуре данных, отсортированные по Frame. Затем вы можете выполнить двоичный поиск, когда вам нужно найти ближайший к данному номеру кадра.

+0

Возможно, посмотрите на коллекцию SortedList как на структуру данных. – Reddog

+0

Не смысл делать это в linq? Как это будет linq? Пример кода? – jsmith

+0

Я был бы в порядке с решением, которое не использует linq. Я просто ищу «простой». – 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

Может быть, вы могли бы разделить большой ITEMLIST в 5 - 10 меньше списков, отсортированных по их Framediff или что-то?

таким образом поиск будет быстрее, если вы знаете, в каком списке нужно искать

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; 
} 
+0

Это в точности как метод MoreLINQ 'MinBy', как это было предложено в ответе dtb. (Хотя 'MinBy' не может иметь специальный случай для раннего выхода для точного соответствия.) – LukeH

+0

Если у вас есть отсортированная коллекция, вы можете получить еще лучший ранний выход. Плюс, если вы используете цикл «for», вы можете вспомнить последний использованный индекс и начать поиск там, а не с начала коллекции. Хороший баланс между простым и быстрым. Это то, что я в конечном итоге решил сделать, хорошо работал. – Phil

Смежные вопросы