2010-06-03 4 views
4

J'ai une collection d'objets, chacun avec une propriété int Frame. Étant donné un int, je veux trouver l'objet dans la collection qui a l'image la plus proche.Recherche avec Linq

Voici ce que je fais jusqu'à présent:

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... 
} 

C'est super et tout, sauf qu'il ya 200.000 articles dans ma collection et j'appelle cette méthode très fréquemment. Y a-t-il un moyen relativement facile et plus efficace de le faire?

+1

est-ce juste LINQ à une collection d'objets ou LINQ à SQL? – Jimmy

+0

"J'ai une collection d'objets", première phrase de la question. ;) – jsmith

Répondre

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

en utilisant MinBy à partir de MoreLINQ.

3

Ce que vous pouvez essayer est de stocker les cadres dans une structure de données triée par Frame. Ensuite, vous pouvez faire une recherche binaire lorsque vous avez besoin de trouver le plus proche d'un frameNumber donné.

+0

Peut-être regarder dans la collection SortedList comme votre structure de données. – Reddog

+0

N'est-ce pas le point de le faire dans linq? Comment cela serait-il linq? Exemple de code? – jsmith

+0

Je serais d'accord avec une solution qui n'utilise pas linq. Je cherche juste "simple". – Phil

0

vous pouvez combiner vos déclarations dans une aile du nez:

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

Je crois que son problème est que ce genre (qui n'est pas vraiment nécessaire) prend beaucoup de temps. – Ghostrider

0

Peut-être que vous pouvez diviser votre grand dans 5 Liste de produits - 10 petites listes qui sont commandés par leur Framediff ou quelque chose?

cette façon, la recherche est plus rapide si vous savez où vous listez devez rechercher

1

Je ne sais pas que j'utiliser LINQ pour cela, du moins pas avec un 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

C'est à peu près la méthode 'MinBy' de MoreLINQ - comme le suggère la réponse de dtb - qui fonctionne. (Bien que 'MinBy' ne puisse pas prendre en compte la sortie anticipée pour une correspondance exacte.) – LukeH

+0

Si vous avez une collection triée, vous pouvez avoir une sortie encore meilleure. De plus, si vous utilisez une boucle "for", vous pouvez vous souvenir du dernier index utilisé et lancer la recherche à partir de là plutôt qu'à partir du début de la collection. Bon équilibre entre simple et rapide. C'est ce que j'ai finalement choisi de faire, qui a bien fonctionné. – Phil