2013-09-06 14 views
7

Ho 2 lista oggetto di tipo di una classe,Come utilizzare variabili locali in un'espressione lambda

class person 
    { 
     public string id { get; set; } 
     public string name { get; set; } 
    } 

List<person> pr = new List<person>(); 
pr.Add(new person { id = "2", name = "rezoan" }); 
pr.Add(new person { id = "5", name = "marman" }); 
pr.Add(new person { id = "3", name = "prithibi" }); 

List<person> tem = new List<person>(); 
tem.Add(new person { id = "1", name = "rezoan" }); 
tem.Add(new person { id = "2", name = "marman" }); 
tem.Add(new person { id = "1", name = "reja" }); 
tem.Add(new person { id = "3", name = "prithibi" }); 
tem.Add(new person { id = "3", name = "prithibi" }); 

ora devo ottenere tutti gli ID da "pr" ListObject che non ha alcuna voce o numero dispari di voci nel "tem" ListObejct. usando lamda.

Per fare questo ho usato,

HashSet<string> inconsistantIDs = new HashSet<string>(pr.Select(p => p.id).Where(p => tem.FindAll(t => t.id == p).Count == 0 || tem.FindAll(t => t.id == p).Count % 2 != 0)); 

e funziona benissimo.

ma si può vedere dal codice ho usato tem.FindAll (t => t.id == p) Count due volte per comapre con == 0 e % 2! = 0.

C'è un modo per utilizzare tem.FindAll (t => t.id == p) Count una sola volta e salvarlo a una variabile temporanea e quindi confrontare questa variabile con == 0 e % 2! = 0.

Più semplicemente voglio solo usarlo una volta per due condizioni qui.

+0

non utilizzare subjjects come "problema di fronte in xxx ", questo sarà il link di Google. –

+0

Hai ottenuto @TimSchmelter – Rezoan

risposta

14

Use a statement lambda instead of an expression lambda

var inconsistantIDs = new HashSet<string>(
      pr.Select(p => p.id).Where(p => 
        { 
        var count = tem.FindAll(t => t.id == p).Count; 
        return count == 0 || count % 2 != 0; 
        } 
      )); 
+0

Ya questo funziona. ma "count .Count% 2! = 0" dovrebbe essere "count% 2! = 0". potresti per favore correggerlo. @Ahmed KRAIEM – Rezoan

+3

Invece di 'FindAll' userei' Count() '. Il primo ha bisogno di creare una nuova collezione per ogni persona. –

+0

@Rezoo corretto. @ Tim È vero. 'var count = tem.Count (t => t.id == p);' –

2
HashSet<string> inconsistantIDs = new HashSet<string>(
    pr.Select(p => new { Id = p.id, Cnt = tem.FindAll(t => t.id == p.id).Count() }) 
     .Where(p => p.Cnt == 0 || p.Cnt % 2 != 0) 
     .Select(p => p.Id); 
+0

Grazie, ma mi sta dando errore su "t.id == p" e ".Count()" dovrebbe essere ".Count". potresti vedere questo problema – Rezoan

+0

Risolto. Ma non userei questo codice se non lo capisci. –

4

Forse semplicemente:

var query = pr.Where(p => { int c = tem.Count(p2 => p.id == p2.id); return c == 0 || c % 2 != 0; }); 

restituisce due persone:

2 "rezoan" 
5 "marman" 
2

Su un lato nota, rigorosamente Per quanto riguarda le prestazioni, si otterrebbero prestazioni migliori se si creava una mappatura hash di ciascun ID al suo conteggio e quindi la si cerca in un ciclo.

In questo momento si ha un algoritmo O(n*m), che sarebbe ridotto a O(n+m):

// create a map (id -> count), O(m) operation 
var dictionary = new Dictionary<string, int>(); 
foreach (var p in tem) 
{ 
    var counter = 0; 
    dictionary.TryGetValue(p.id, out counter); 
    counter++; 
    dictionary[p.id] = counter; 
} 

// search the map, O(n) operation 
var results = new HashSet<string>(); 
foreach (var p in pr) 
{ 
    var counter = 0; 
    dictionary.TryGetValue(p.id, out counter); 
    if (counter == 0 || counter % 2 != 0) 
     results.Add(p.id); 
} 
+0

Grazie per le tue preziose informazioni.+1 @Groo – Rezoan

3

Oltre dichiarazione lambda è possibile utilizzare let clause:

HashSet<string> inconsistantIDs = new HashSet<string>(
    from p in pr 
    let count = tem.FindAll(t => t.id == p).Count 
    where count == 0 || count % 2 != 0 
    select p.id 
); 
Problemi correlati