2013-09-06 21 views
7

Mam 2 listy obiekt typu jakiejś klasy,Jak używać zmiennych lokalnych w wyrażeniu 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" }); 

teraz muszę uzyskać wszystkie identyfikatory z „pr” ListObject że ma żadnego wpisu lub nieparzysta liczba wpisów w "tem" ListObejct. używając lamda.

W tym celu użyłem,

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

i działa dobrze.

ale widać z kodu Użyłem tem.FindAll (t => t.id == p) .Count dwukrotnie comapre z == 0 i % 2! = 0.

Czy jest jakiś sposób na wykorzystanie tem.FindAll (t => t.id == P) .Count raz i zapisać go do zmiennej tymczasowej, a następnie porównać tę zmienną z == 0 i % 2! = 0.

Po prostu chcę go użyć raz na dwa warunki tutaj.

+0

Proszę nie używać subjjects jako „problem skierowaną w xxx ", będzie to link google. –

+0

Got u @TimSchmelter – Rezoan

Odpowiedz

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 to działa. ale "count .Count% 2! = 0" powinno być "count% 2! = 0". czy mógłbyś to poprawić? @Ahmed KRAIEM – Rezoan

+3

Zamiast 'FindAll' użyłbym' Count() '. Ten pierwszy musi stworzyć nową kolekcję dla każdej osoby. –

+0

@Rezoan Corrected. @Tim To prawda. '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

Dzięki, ale daje mi błąd na "t.id == p" i ".Count()" powinno być ".Count". czy możesz zobaczyć ten problem. – Rezoan

+0

Naprawiono. Ale nie użyłbym tego kodu, jeśli go nie rozumiesz. –

4

Może po prostu:

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

powraca dwie osoby:

2 "rezoan" 
5 "marman" 
2

Na marginesie, ściśle Jeśli chodzi o wydajność, uzyskasz lepszą wydajność, jeśli utworzysz mapowanie hasłowe dla każdego identyfikatora, a następnie przeszukasz je w pętli.

Teraz masz O(n*m) algorytmu, który zostanie zmniejszony do 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

Dziękujemy za cenne informacje.+1 @Groo – Rezoan

3

Poza rachunku lambda można używać 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 
); 
Powiązane problemy