I am matching requests with responses based on requestId as follows:
    public void MatchCallPairsByRequestId()
    {
        // Finds request that have matching response based on RequestId and create callpair
       _callPairs = _requests.Where(req => !string.IsNullOrEmpty(req.RequestId))
                  .Join(_responses, 
                        req => req.RequestId,
                        resp => resp.RequestId,
                        (req, resp) => new CallPair(req, resp)).ToList();
    }
or in LINQ expression:
 _callPairs = (from req in _requests
                  join resp in _responses
                      on req.RequestId equals resp.RequestId
                      where !string.IsNullOrEmpty(req.RequestId)
                  select new CallPair(req, resp)).ToList();
Now I want to collect the requests and responses that are not matched by the function in a separate list called nonMatchedRequests and nonMatchedResponses. How do I use this query to collect the remainder in a separate list?
I'm not sure if there is a way to do this in one call or perhaps even merge it with producing the list of pairs, but you can run a couple of follow up methods to determine the unmatched items:
var unmatchedRequests = _requests.Except(_callPairs.Select(cp => cp.Request));
var unmatchedResponses = _responses.Except(_callPairs.Select(cp => cp.Response));
The documentation for Enumerable.Join also talks of being able to use GroupJoin to perform an outer join, as detailed here, this will return unmatched requests, though I think it would miss unmatched responses.
I await with bated breath the answer demonstrating linq wizardry that does this more efficiently with one call.
You probably can do this through .Except(), maybe also operating on distinct values
// Matching pairs
_callPairs = _requests.Where(req => !string.IsNullOrEmpty(req.RequestId))
    .Join(
        _responses, 
        req => req.RequestId,
        resp => resp.RequestId, 
        (req, resp) => new CallPair(req, resp)
    ).ToList();
// To use the .Distinct() part, you're going to need to implement IEqualityComparer twice
// Easy but maybe not strictly necessary, no matter what it would be a solid approach
var matchedRequests = _callPairs.Select(cp => cp.Request); //.Distinct(new RequestComparer());
var matchedResponses = _callPairs.Select(cp => cp.Response); //.Distinct(new ResponseComparer());
var nonMatchingRequests = _requests.Except(matchedRequests);
var nonMatchingResponses = _responses.Except(matchedResponses);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With