Afshin Ghazi
Afshin Ghazi

Reputation: 2990

Use Linq and Lambda to include default

I have two lists: relatedContact and fileContactIds. I am using the query to loop the relatedContacts list and return value of userClientCode (which I will make the image name) only if it is also in the fileContactIds list. How can I put in a value (eg: "Default") if the value isn't in the second list ?

var result = relatedContact.SelectMany(rc => rc.contacts.Select(pc => new RelatedContactsDescription
                {
                    imageUrl = mappedRelatedContactsPath + pc.userclientcode + ".jpg",
                    userclientcode = pc.userclientcode,
                    description = rc.clienttaxonomy,
                    fullname = pc.fullname,
                    email = pc.contactdetails != null && pc.contactdetails.Count >= 1 ? pc.contactdetails[0].contactdata : "",
                    address = pc.contactdetails != null && pc.contactdetails.Count >= 2 ? pc.contactdetails[1].contactdata : "",
                    phoneNumber = pc.contactdetails != null && pc.contactdetails.Count >= 3 ? pc.contactdetails[2].contactdata : "",
                    populated = string.IsNullOrEmpty(pc.userclientcode) ||
                                string.IsNullOrEmpty(pc.fullname) ||
                                string.IsNullOrEmpty(pc.contactdetails[0].contactdata) ? false : true,
                }))
                .Where(el => fileContactIds.Contains(el.userclientcode)).ToList();

I have read: Lambdas and Linq and Joins First or Default etc but all I can see is how to get matching data from both not also how to put a "fall-back" or default value if they don't match.

Thanks in advance

Upvotes: 2

Views: 1333

Answers (1)

Mrinal Kamboj
Mrinal Kamboj

Reputation: 11478

In your current code do the following changes:

  • Remove the Where clause, as that's not serving the purpose, you need Default where UserClientCode doesn't exist, you don't want to filter them out using Where

  • Change the following in SelectMany call:

    userclientcode = pc.userclientcode

To

 userclientcode = fileContactIds.Contains(pc.userclientcode) ? 
                  pc.userclientcode : "Default"

You may consider using a Left Join post creating a flattened list using SelectMany, but that would be a Round about way to achieve it, which is simply achieve while creating a flattened List.

Using Left Join

Following is the code option for Left Join, it needs GroupJoin in C#:

var result = relatedContact.SelectMany(rc => rc.contacts.Select(pc => {pc})
                           .GroupJoin(fileContactIds, pc => pc.userclientcode,
                                      fc => fc.ContactId,new {pc,fc})
                           .SelectMany(
                            x => x.fc.DefaultIfEmpty()
                            (x,y) => new RelatedContactsDescription
                            {
                               userclientcode = (y == null) ? "Default":x.pc.userclientcode,
                            .........(fill remaining as per original logic)
                            });

How does it work

  • Create Anonymous List from relatedContact using SelectMany
  • GroupJoin with fileContactIds. where I have assume field is ContactId
  • Create an Anonymous List with Data from both collections, where Unmatched records from fileContactIds will be empty being LeftJoin
  • In final SelectManyexplicity make the fileContactIds empty values null, then during data selection, so what I have suggested earlier for null values, fill "Default", else the specific value

Upvotes: 3

Related Questions