2009-04-02 5 views
3

Cela a l'habitude de travailler pour moi, puis il a échoué. Je veux retourner uniquement les éléments qui contiennent tous les filtres, pas au moins un filtre comme c'est le cas maintenant. Qu'est-ce qui ne va pas ici?Filtrer une collection d'éléments à partir du contenu d'une autre collection

private IQueryable<IndexItem> FilteredIndex (IQueryable<IndexItem> index, IEnumerable<string> filters) 

    { 

     var filteredIndex= from f in filters.AsQueryable() 
       where f.Length>0 
       from i in index 
       where i.FilterNames.Contains(f) 
       select i; 
     return filteredIndex; 
    } 
+0

Quel fournisseur LINQ utilisez-vous? Je suppose que ce n'est pas LINQ to Objects, basé sur l'utilisation de IQueryable. –

+0

Je peux donner une solution assez élégante pour LINQ to Objects, mais je ne suis pas sûr que cela fonctionne pour vous. Laissez-moi entendre si c'est le cas. –

Répondre

1

Que diriez-vous quelque chose comme:

foreach(string s in filters) { 
    if(s.Length == 0) continue; 
    string tmp = s; // because of "capture" problem 
    index = index.Where(i => i.FilterNames.Contains(tmp)); 
} 
return index; 

Cette applique une succession de Where clauses, couvrant tous les filtres - essentiellement AND.

+0

qu'est ce que "capture"? – zsharp

+0

@zsharp le lambda à l'intérieur de Où() est une fermeture. la variable s de cette itération doit être conservée sinon elle sera différente au moment où lambda est exécutée. Voir les fermetures. – CVertex

+0

Parce que nous utilisons "s" dans un lambda, il est en fait traité (par le compilateur) comme un champ sur une classe générée par le compilateur (pour des raisons complexes). Le problème est que la nature de "foreach" signifie que, sinon, vous en obtiendriez seulement un, et vous auriez n fois Où ([dernier filtre]). –

1

Retournez-le. Ce que vous voulez, c'est ces éléments dans l'index où chaque élément dans FilterNames a une entrée correspondante dans les filtres. Je ne suis pas sûr à quel point ce serait performant, mais une comparaison de comptes devrait faire. Quelque chose comme:

private IQueryable<IndexItem> FilteredIndex(IQueryable<IndexItem> index, IEnumerable<string> filter) 
{ 
    var filteredIndex = from i in index 
         where (from s in i.FilterNames 
           where filter.Contains(s) 
           select s).Count() == i.FilterNames.Count 
         select i; 
    return filteredIndex; 
} 
3

Droit devant. Pour un élément donné de l'index, vérifiez qu'il est vrai pour tous les filtres que l'élément donné contient le filtre. Avec ceci, sélectionnez simplement tous les éléments de l'index pour que la condition donnée soit vraie. Je ne suis pas sûr si le contrôle de la longueur supérieure à zéro est nécessaire, l'écrou est facilement intégré.

index.Where(item => 
    filters.All(filter => 
     (filter.Length > 0) || (item.FilterNames.Contains(filter)))) 

Il travaille avec LINQ aux objets et je suppose qu'il fait ce que vous voulez, mais je ne sais pas si cela fonctionne avec LINQ to SQL.

Questions connexes