7

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.

1
  • Please don't use subjjects as "facing issue in xxx", that will be the google-link. Commented Sep 6, 2013 at 12:26

5 Answers 5

17

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;
                  }
           ));
Sign up to request clarification or add additional context in comments.

3 Comments

Ya this works. but "count .Count % 2 != 0" should be "count% 2 != 0". could you please just correct it. @Ahmed KRAIEM
Instead of FindAll i would use Count(). The former needs to create a new collection for every person.
@Rezoan Corrected. @Tim That's true. var count = tem.Count(t => t.id == p);
4

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"

Comments

4

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

Comments

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

2 Comments

Thanks but its giving me error on "t.id == p" and ".Count()" should be ".Count". could you please see this issue.
Fixed. But I wouldn't use this code if you don't understand it.
2

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

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.