3

I have been trying to get the title, description, start and end date in the periods array based on the time given, I have the following JSON data (the variable name of the following is _json):

Update:

What I want to do is to get the title, description, start and enddate in the periods json array, the condition of it will be based on the start and enddate in the periods json array.

[
    {
        "ID": "1",
        "Title": "First Title",
        "Description": "First Description",
        "Periods": [
            {
                "StartDate": "2017-04-23 15:30",
                "EndDate": "2017-04-23 15:40"
            },
            {
                "StartDate": "2017-04-23 15:42",
                "EndDate": "2017-04-23 15:45"
            },
            {
                "StartDate": "2017-04-23 15:47",
                "EndDate": "2017-04-23 15:50"
            }
        ]
    },
    {
        "ID" : "2",
        "Title": "Second Title",
        "Description": "Second Description",
        "Periods": [
            {
                "StartDate": "2017-04-23 15:52",
                "EndDate": "2017-04-23 15:55"
            },
            {
                "StartDate": "2017-04-23 15:57",
                "EndDate": "2017-04-23 16:00"
            },
            {
                "StartDate": "2017-04-23 16:02",
                "EndDate": "2017-04-23 16:05"
            }
        ]
    }
]

And here is my code:

public sealed class Information
{
    public List<Period> Periods;
    public string Title;
    public string Description;
    public int ID;
}

public sealed class Period
{
    public DateTime StartDate;
    public DateTime EndDate;
}

var informations = JsonConvert.DeserializeObject<List<Information>>(_json);

var information = GetData(informations, DateTime.Now);

private Information GetData(List<Information> informations, DateTime dateToCheck)
{
    return informations.Select(x =>
    {
        x.Periods = x.Periods
                     .TakeWhile(y => dateToCheck >= y.StartDate 
                                  && dateToCheck < y.EndDate)
                     .ToList();

        if (x.Periods.Count > 0)
           return x;
        else
            return null;
     }).FirstOrDefault();
 }

However, it only take the first array (ID: 1) of the JSON data and the first array of the Periods inside the JSON data, even the DateTime.Now is more than 2017-04-23 15:40 or it is 2017-04-23 15:52, it will return null.

Do I filtering not correct for the LINQ or in the between time condition?

Your answer much appreciated.

Second Update:

enter image description here

The expected output will be like:

  • Have the JSON data, which where the between date time is falling into, for example: between date time is falling into "ID: 2", and "Periods: 2017-04-23 15:57", then it will only return JSON of ID no 2 and falling Periods (in this case 2017-04-23 15:57 as StartDate, and 2017-04-23 16:00 as EndDate), while the rest of the Periods is removed. So it will be like this (It is based on the Periods, which where the date time is falling to, and it will determine which data need to get).

    "ID" : "2",
    "Title": "Second Title",
    "Description": "Second Description",
    "Periods": [ {
       "StartDate": "2017-04-23 15:57",
       "EndDate": "2017-04-23 16:00" }
    

Thanks

3 Answers 3

2

Problem with your query is TakeWhile, as per MSDN:-

Returns elements from a sequence as long as a specified condition is true. The element's index is used in the logic of the predicate function.

So in your query it is only checking untill it finds the correct match and after that it ignores all data. Instead you need to check your condition in entire periods.

You can simplify your query using FirstOrDefault and it should give you the correct result:-

return informations.FirstOrDefault(y => dateToCheck >= y.StartDate 
                                        & dateToCheck < y.EndDate);

This will return null if no match is found otherwise the first Information object if it finds a match.

If you want to return all matching Periods then use Where instaed and your method return type should change to IEnumerable<Information> instead of Information.

Sign up to request clarification or add additional context in comments.

4 Comments

@Serenity - Not a problem. I am glad it helped you.
Hi, after i tested it again, the Periods is now working, but the Information is only looking through the first data of JSON, after I made the function to be IEnumerable<Information>, it looping through the list of JSON data, but it didn't stop until the last array of JSON being looping through, back to my question above: - What I want to do is to get the title, description, start and enddate in the periods json array, the condition of it will be based on the start and enddate in the periods json array. Thanks
@Serenity - I am not clear what you mean by the condition of it will be based on the start and enddate in the periods json array. Can you show the expected output you are looking for based on your input. It will make it more clear.
Hi, I already post the image on my question above. Please help to look on it and the expected output. Thanks
1

I think that instead of TakeWhile you need a Where:

x.Periods = x.Periods
             .Where(y => dateToCheck >= y.StartDate 
                      && dateToCheck < y.EndDate)
             .ToList();

Keep in mind that TakeWhile stops when the condition is false. If you need a more formal explanation, you can find here that:

The TakeWhile(IEnumerable, Func) method tests each element of source by using predicate and yields the element if the result is true. Enumeration stops when the predicate function returns false for an element or when source contains no more elements.

Update

private Information GetFirstMatchingInformationByPeriod(
    List<Information> informations
    , DateTime dateToCheck)
{
    // Find the first information that match your search criteria
    var information = informations.FirstOrDefault(information 
                                                  => information.Periods                                                                         
                                                                .Any(period
                                                    => period.dateToCheck >= period.StartDate 
                                                    && period.dateToCheck < period.EndDate);

    // If not any found, return null.
    if(information == null) return null;

    var firstMatchingPeriod = information.Periods
                                         .First(period => dateToCheck >= period.StartDate 
                                                       && dateToCheck < period.EndDate);

     // Information found. 
     // Change it's periods with a List containin only the first matching period. 
     information.Periods = new List<Period>{ firstMatchingPeriod } ;
     return information;
}

6 Comments

@Serenity You are welcome ! I am glad that I helped :)
Hi, after i tested it again, the Periods is now working, but the Information is only looking through the first data of JSON, after I made the function to be IEnumerable<Information>, it looping through the list of JSON data, but it didn't stop until the last array of JSON being looping through, back to my question above: - What I want to do is to get the title, description, start and enddate in the periods json array, the condition of it will be based on the start and enddate in the periods json array. Thanks
@Serenity please check my update. I think that you want is this and let me know. Thanks
Hi, I already post the image on my question above. Please help to look on it and the expected output. Thanks. Unfortunately, your update is not working for me, it gets the list of Information JSON array. Sorry and Thanks for your help.
@Serenity I am sorry but it is still unclear to me what you are looking for? Do you want the first matching period if there is any at all for each ID? Do you want the first matching period if there is any at all from any ID, (If you have the ids 1,2,3,4 & 5 and for the ids 2 & 4 there is a matching period, you want to get ONLY the matching period of the id 2, because it will be processed first)?
|
0

There is a much more readable way to write your query (that works):

private static Information GetData(List<Information> informations, DateTime dateToCheck)
{
    return (from info in informations
            from period in info.Periods
            where dateToCheck >= period.StartDate &&
                  dateToCheck < period.EndDate
            select info).FirstOrDefault();
}

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.