2008-11-05 4 views
20

Dire que j'ai une liste de tous Projects, et ce groupe je les par Category comme ceci:Obtenir impair/même une partie d'une séquence avec LINQ

var projectsByCat = from p in Projects 
        group p by p.Category into g 
        orderby g.Count() descending 
        select new { Category = g.Key, Projects = g }; 

Maintenant, je veux afficher cela comme une liste dans un page web, où d'abord je crée le div côté gauche, d'autre part le div côté droit. Je commande par numéro de Projects dans chaque Category pour montrer le Categories avec le plus Projects sur le dessus - donc je voudrais diviser projectsByCat en deux - si je mets tous les "numéros impairs" Categories sur la gauche et le "pair" catégories sur la droite, je pense que je vais avoir une vue raisonnablement saine.

Je pensais que je pouvais faire pour obtenir les paires et impaires membres de projectsByCat:

var oddCategories = projectsByCat.Where((cat, index) => index % 2 != 0); 

var evenCategories = projectsByCat.Where((cat, index) => index % 2 == 0); 

Et il compile - cependant, quand je le lance, je reçois une exception telle que celle-ci:

Surcharge non prise en charge utilisée pour l'opérateur de requête 'Where'.

Et je pensais que j'étais en sécurité car il a compilé en premier lieu ..;)

Y at-il une façon élégante de le faire? Et aussi, y a-t-il une explication élégante pour pourquoi mon utilisation créative de Where() ne fonctionnera pas?

Merci d'avance!

Répondre

35

Si vous utilisez SQL ou à LINQ LINQ to Entities vous devez d'abord pleinement matérialiser les résultats en mémoire:

var oddCategories = projectsByCat.ToList().Where((c,i) => i % 2 != 0); 
var evenCategories = projectsByCat.ToList().Where((c,i) => i % 2 == 0); 

Il est impossible de parcourir les résultats sur la base de données avec un indexeur sans l'utilisation d'un curseur, que la structure ORM fait fait pas faire.

+0

qui l'a fait - je 95% LINQ aux objets ainsi la possibilité de cet être un problème avec LINQ to SQL ne même pas frappe moi, merci! –

21

Notez qu'appeler deux fois le même .ToList() pour interroger la base de données lance deux requêtes sur la base de données.

Il serait préférable de mettre en cache le résultat dans une liste intermédiaire, puis appliquez votre filtrage prédicat:

var projectsByCat = 
    (from p in Projects 
    group p by p.Category into g 
    orderby g.Count() descending 
    select new { Category = g.Key, Projects = g }).ToList(); 

var oddCategories = projectsByCat.Where((cat, index) => index % 2 != 0); 
var evenCategories = projectsByCat.Where((cat, index) => index % 2 == 0); 
5

Les oddCategories et les evenCategories sont en arrière.

Index commencent un 0 non 1

0% 2 = 0

0 index est impair.

var oddCategories = projectsByCat.Where((cat, index) => index % 2 == 0); 

var evenCategories = projectsByCat.Where((cat, index) => index % 2 != 0); 
2

La bonne façon de le faire en utilisant LINQ, et en évitant les multiples énumérations sur l'entrée, est de faire un groupe ou similaire si chaque élément est pair ou impair.

Une façon simple en utilisant la surcharge pour Select qui mixes in an index couplé avec ToLookup vous donne ce que vous voulez:

var oddsAndEvens = input 
    .ToList() // if necessary to get from IQueryable to IEnumerable 
    .Select((item, index) => new { isEven = index % 2 != 0, item }) 
    .ToLookup(
     i => i.isEven, 
     i => i.item); 

Cela produira une structure de données Lookup<TKey, TElement> qui a le following benefit:

Si la La clé est introuvable dans la collection, une séquence vide est renvoyée.

Cela signifie que, après la requête de LINQ ci-dessus, vous pouvez faire:

var evens = oddsAndEvens[true]; 
var odds = oddsAndEvens[false]; 
0

Vous pouvez séparer étrange et même dans votre vue LINQ.

//even 
@foreach (var item in Model.Where((item, index) => index % 2 == 0)) 
{ 
    //do the code 
} 

//odd 
@foreach (var item in Model.Where((item, index) => index % 2 != 0)) 
{ 
    //do the code 
} 
0

var s = "Ceci est un test < chaîne > pour extraire l'index < impairs > valeurs après split"; var l = s.Split (nouveau char [] {'<', '>'}; IEnumerable e = l.Où (x => ((l.ToList(). IndexOf (x)% 2) == 1)); 'e' serait: 'string' et 'index'

Questions connexes