2010-05-19 6 views
1

Considérons la nécessité de rechercher une liste de clients par nom et prénom. Le souhait est que la liste des résultats soit triée par le client ayant le plus de correspondances dans les termes de recherche.LINQ OrderBy: meilleurs résultats de recherche en haut de la liste de résultats

 
FirstName  LastName 
----------  --------- 
Foo   Laurie 
Bar   Jackson 
Jackson  Bro 
Laurie   Foo 
Jackson  Laurie 
string[] searchTerms = new string[] {"Jackson", "Laurie"}; 

//want to find those customers with first, last or BOTH names in the searchTerms 
var matchingCusts = Customers 
         .Where(m => searchTerms.Contains(m.FirstName) 
           || searchTerms.Contains(m.LastName)) 
         .ToList(); 

/* Want to sort for those results with BOTH FirstName and LastName 
    matching in the search terms. Those that match on both First and Last 
    should be at the top of the results, the rest who match on 
    one property should be below. 
*/ 

return matchingCusts.OrderBy(m=>m); 

désiré Trier:

Jackson  Laurie (matches on both properties) 
Foo   Laurie 
Bar   Jackson 
Jackson  Bro 
Laurie   Foo 

Comment puis-je obtenir cette fonctionnalité désirée avec LINQ et OrderBy/OrderByDescending?

+1

Envisagez d'utiliser la recherche en texte intégral pour des choses comme ceci: http://msdn.microsoft .com/fr-us/library/ms142571.aspx –

Répondre

9

Utilisez Select pour projeter une « évaluation match » avec le client, puis par ordre que:

class Program 
{ 
    static void Main(string[] args) 
    { 
     var Customers = new Customer[] 
     { 
      new Customer { FirstName = "Foo", LastName = "Laurie" }, 
      new Customer { FirstName = "Bar", LastName = "Jackson" }, 
      new Customer { FirstName = "Jackson", LastName = "Bro" }, 
      new Customer { FirstName = "Laurie", LastName = "Foo" }, 
      new Customer { FirstName = "Jackson", LastName = "Laurie" }, 
     }; 

     string[] searchTerms = new string[] { "Jackson", "Laurie" }; 

     //want to find those customers with first, last or BOTH names in the searchTerms 
     var matchingCusts = Customers 
           .Where(m => searchTerms.Contains(m.FirstName) 
             || searchTerms.Contains(m.LastName)) 
           .ToList(); 

     var result = matchingCusts.Select(x => new 
      { 
       Customer = x, 
       MatchEvaluation = (searchTerms.Contains(x.FirstName) ? 1 : 0) + (searchTerms.Contains(x.LastName) ? 1 : 0), 
      }) 
      .OrderByDescending(x => x.MatchEvaluation) 
      .Select(x => x.Customer); 

     foreach (var c in result) 
     { 
      Console.WriteLine(c.FirstName + " " + c.LastName); 
     } 

     Console.ReadKey(); 
    } 

    public sealed class Customer 
    { 
     public string FirstName { get; set; } 
     public string LastName { get; set; } 
    } 
} 
+1

Remarque: la seule raison pour laquelle j'appelle 'ToList' est de tirer les résultats de la base de données, donc l'évaluation et le tri des correspondances sont effectués en utilisant LINQ to Objects. S'il n'y a pas de DB, le 'ToList' est inutile. –

0

Vous pouvez faire votre propre IEqualityComparer<Customer> de passer dans les fonctions de OrderBy.

Faites en sorte que le constructeur prenne la liste des critères de recherche, puis donne la priorité au confinement par ordre alphabétique.

Ensuite, faites .SortBy(c => c.LastName, new MyEqualityComparer(searchTerms)).ThenBy(c => c.FirstName, new MyEqualityComparer(searchTerms))

+0

Je pense que vous voulez dire 'IComparer ' plutôt que 'IEqualityComparer '. –

4

Depuis que je totalement raté la question initiale:

une doublure :)

var matchingCusts = Customers 
    .Where(m => searchTerms.Contains(m.FirstName) || 
       searchTerms.Contains(m.LastName)) 
    .Select(c => new 
    { 
     Customer = c, 
     Sort = ((searchTerms.Contains(c.FirstName) ? 0 : 1) + 
       (searchTerms.Contains(c.LastName) ? 0 : 1)) 
    }) 
    .OrderBy(o => o.Sort) 
    .ThenBy(o1 => o1.Customer.LastName) 
    .ThenBy(o2 => o2.Customer.FirstName) 
    .Select(r => r.Customer); 
Questions connexes