Rezoan
Rezoan

Reputation: 1787

How to use local variables in a lambda expression

I have 2 list object of type of some class,

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

Now i have to get all the ids from "pr" ListObject that has no entry or odd number of entries in the "tem" ListObejct. using lamda.

To do this i have used,

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

and it works fine.

but you can see from the code i have used tem.FindAll(t => t.id == p).Count twice to comapre with ==0 and %2!=0.

Is there any way to use tem.FindAll(t => t.id == p).Count once and save it to a temporary variable and then compare this variable with ==0 and %2!=0.

More simply i just want to use it once for two condition here.

Upvotes: 7

Views: 9749

Answers (5)

Ahmed KRAIEM
Ahmed KRAIEM

Reputation: 10427

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

Upvotes: 16

Vladimir
Vladimir

Reputation: 7475

Besides statement lambda you can use 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
);

Upvotes: 4

vgru
vgru

Reputation: 51204

On a side note, strictly performance wise, you would get better performance if you created a hash mapping of each ID to its count and then search it in a loop.

Right now you have a O(n*m) algorithm, which would be reduced to 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);
}

Upvotes: 2

Keith Payne
Keith Payne

Reputation: 3082

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

Upvotes: 2

Tim Schmelter
Tim Schmelter

Reputation: 460028

Perhaps simply:

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

returns two persons:

2   "rezoan"
5   "marman"

Upvotes: 4

Related Questions