2

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

Community
  • 1
  • 1
Afshin Ghazi
  • 2,784
  • 4
  • 23
  • 37

1 Answers1

3

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
Mrinal Kamboj
  • 11,300
  • 5
  • 40
  • 74
  • I still think He should use left join – Inside Man Nov 12 '16 at 07:18
  • What I have suggested is much simpler and would be done while creating the final list. As I have suggested, yes `Join` is an option but its the matter of simplicity in my view – Mrinal Kamboj Nov 12 '16 at 07:59
  • @Stranger check out the code for Left Join too, which is achieved using `GroupJoin` – Mrinal Kamboj Nov 12 '16 at 08:45
  • @Stranger Also Check I have explained its working, this is good example: http://www.advancesharp.com/blog/1108/linq-inner-join-left-outer-join-on-two-lists-in-c-with-example – Mrinal Kamboj Nov 12 '16 at 08:53
  • @MrinalKamboj I am trying to implement your first suggestion but on getting what you mean when you say remove Where clause. Do you mean after Select I should then filter ? Also your left join is showing many errors and extra brackets are inserted. Also please remember I don't just want the userclientcode, I want to match this to the contactId and map into RelatedContactsDescription object – Afshin Ghazi Nov 14 '16 at 07:55
  • @AfshinGhazi, its like, `Where` clause in your code is only for the purpose of filtering the `Ids` based on `fileContactIds`, but your challenge is you want Default value for Ids which doesn't exist, not just filter them out, so I have shifted the filtering inside the `SelectMany` and `Where` clause is redundant as it cannot help you to get the Default values. – Mrinal Kamboj Nov 14 '16 at 08:09