user2609980
user2609980

Reputation: 10484

How to match all objects from two lists into pairs of two based on proximity of DateTime values

I have two lists of Requests and Responses who inherit from the abstract AbstractLineModel class. Both the responses and requests contain a DateTime (or not) named DateTime, MethodName, and a GUID.

A CallPair contains a matching pair of Request and a Response:

public class CallPair
{
    public AbstractLineModel _request { get; set; }
    public AbstractLineModel _response { get; set; }

    public CallPair(AbstractLineModel request, AbstractLineModel response)
    {
        _request = request;
        _response = response;
    }
}

The class CallPairOrganizer organizes the calls into the following lists:

public class CallPairOrganizer
{
    // List of requests and matching responses
    private List<CallPair> _callPairs = new List<CallPair>();
    private List<AbstractLineModel> _lines = new List<AbstractLineModel>();
    private List<AbstractLineModel> _requests = new List<AbstractLineModel>();
    private List<AbstractLineModel> _responses = new List<AbstractLineModel>();
    private List<AbstractLineModel> _unmatchedRequests = new List<AbstractLineModel>();
    private List<AbstractLineModel> _unmatchedResponses = new List<AbstractLineModel>();
}

These are two methods of the CallPairOrganizer class: (1) With the help of an earlier answer I have made a List of CallPairs where the Request with the same GUID as the Response are matched in the Callpair:

public void MatchCallPairsByRequestId()
{
    // Finds request that have matching response based on RequestId and create 
    // callpair
    _callPairs = _requests.Distinct().Where(req => !string.IsNullOrEmpty
                     (req.RequestId))
         .Join(_responses.Distinct(),
               req => req.RequestId,
               resp => resp.RequestId,
               (req, resp) => new CallPair(req, resp)).ToList();

    CollectUnmatchedCalls();
}

And (2) I collect all unmatched requests and responses as follows:

public void CollectUnmatchedCalls()
{
    _unmatchedRequests = 
         _requests.Except(_callPairs.Select(cp => cp._request)).ToList();
    _unmatchedResponses = _responses.Except(_callPairs.Select(cp => 
           cp._response)).ToList();
}

This works. The next step is to compare the unmatched requests and responses and sort them based on DateTime property if they are of the same MethodName. If a request and response are closest to each other I want to match them into a CallPair.

With this part I have a difficult time trying to figure out what algorithm/linq to use. I hope someone can provide me with insights on how to accomplish this task of matching a request with response of the same MethodName if they are close to each other based on DateTime.

Upvotes: 1

Views: 650

Answers (1)

Dave Bish
Dave Bish

Reputation: 19646

So, you need to find the "closest" response, to a request?

//just some objects for me to play with
var requests =  Enumerable.Range(1).Select(i => new { Time = DateTime.Now, Method = "blah" }).ToList();
var responses =  Enumerable.Range(1).Select(i => new { Time = DateTime.Now, Method = "blah" }).ToList();

foreach (var req in requests)
{
    //In all of the responses - find the one that happened soonest after the request (with the same method name)
    var closestResponse = responses
        .Where(resp => resp.Method == req.Method)
        .OrderBy(resp => resp.Time - req.Time)
        .FirstOrDefault();

    //No more responses - exit
    if(closestResponse == null)
        break;

    responses.Remove(closestResponse);

    //make new call pair, with the closest rseponse
}

Upvotes: 2

Related Questions