Ottenere parti pari / dispari di una sequenza con LINQ

Diciamo che ho un elenco di tutti i Projects e che li raggruppo per Category questo modo:

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

Ora voglio mostrarlo come una lista in una pagina web, dove prima creo il div laterale sinistro, in secondo luogo il div laterale destro. Sto ordinando per numero di Projects in ciascuna Category per mostrare le Categories con il maggior numero di Projects in cima – quindi mi piacerebbe dividere projectsByCat in due – se metto tutte le categorie “dispari numerate” a sinistra e “pari numerate” categorie a destra, penso che otterrò una visione ragionevolmente sana.

Quindi pensavo di poterlo fare per ottenere i membri dispari e addirittura dei projectsByCat :

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

E compila – tuttavia, quando lo eseguo, ottengo un’eccezione come questa:

Sovraccarico non supportato utilizzato per l’operatore di query “Dove”.

E pensavo di essere al sicuro dal momento che ha compilato in primo luogo ..;)

C’è un modo elegante per farlo? E inoltre, c’è una spiegazione elegante del perché il mio uso creativo di Where() non funziona?

Grazie in anticipo!

Se stai usando LINQ to SQL o LINQ alle Entities dovresti prima materializzare i risultati in memoria:

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

Non è ansible iterare i risultati sul database con un indicizzatore senza l’uso di un cursore, cosa che il framework ORM non esegue.

Notare che chiamare .ToList() due volte per la stessa query .ToList() la query sul database due volte.

Sarebbe molto meglio memorizzare nella cache il risultato in una lista intermedia, quindi applicare il filtraggio dei predicati:

 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); 

Le oddCategories e le evenCategories sono arretrate.

Gli indici iniziano a 0 non 1

0% 2 = 0

0 indice è dispari.

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

Il modo corretto per farlo usando LINQ ed evitando più enumerazioni sull’input, è di fare un raggruppamento o simili sul fatto che ciascun elemento sia pari o dispari.

Un modo semplice usando il sovraccarico per Select che si mescola in un indice accoppiato con ToLookup ti dà quello che vuoi:

 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); 

Ciò produrrà una struttura di dati di ricerca Lookup che presenta il seguente vantaggio :

Se la chiave non viene trovata nella raccolta, viene restituita una sequenza vuota.

Ciò significa che dopo la query LINQ sopra puoi fare:

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

È ansible separare i punti dispari e pari nella vista usando 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 } 

var s = “questo è un test < string > per estrarre i valori dispari < index > dopo lo split"; var l = s.Split (nuovo char [] {'<', '>'}; IEnumerable e = l.Where (x => ((l.ToList (). IndexOf (x)% 2) == 1) ); 'e' sarebbe: 'stringa' e 'indice'

È ansible trovare anche numeri dispari senza ciclo foreach

 static void Main(string[] args) { List lstnum = new List { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; List lstresult = lstnum.FindAll(x => (x % 2) == 0); lstresult.ForEach(x => Console.WriteLine(x)); }