Reading JSON data and processing data to get a specific value based on conditions

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

Update:

What I want to do is get title, description, start and end in json periods array, which condition will be based on start and end in json periods 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 accepts the first array (ID: 1) of JSON data and the first array. Periods inside the JSON data, even DateTime.Now is greater than 2017-04-23 15:40 or it is 2017-04-23 15:52 , it will return null.

Am I filtering wrong for LINQ or in a time-lapse?

I liked your answer very much.

Second update:

enter image description here

The expected output will look like this:

  • Have JSON data which time between date refers, for example: between date time falls to "ID: 2" and "Periods: 2017-04-23 15:57" , then it will only return JSON ID # 2 and falling periods (in in this case 2017-04-23 15:57 as StartDate and 2017-04-23 16:00 as EndDate ), and the rest of the periods will be deleted. So it will be (it is based on the Periods to which the date time belongs and will determine what data needs to be obtained).

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

thank

+3


source to share


3 answers


I think that instead TakeWhile

you need Where

:

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

      

Be aware that it TakeWhile

stops when the condition is false. If you require a more formal explanation, you can find here that:



The TakeWhile (IEnumerable, Func) method checks each element of the source using a predicate and returns if the result is correct. The enumeration stops when the predicate function returns false for an element, or when the 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 periods with a List containin only the first matching period. 
     information.Periods = new List<Period>{ firstMatchingPeriod } ;
     return information;
}

      

+1


source


The problem with your TakeWhile request , according to MSDN: -

Returns elements from a sequence if the specified condition is true. The element index is used in the function predicate logic.

This way, in your request, it only checks until it finds a correct match, and after that it ignores all data. Instead, you need to check your overall condition periods

.

You can simplify your query by using FirstOrDefault

and it should give the correct result: -



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

      

This will return null if no match is found otherwise than the first object Information

if it finds a match.

If you want to return all matching periods

, use Where

instaed and the return type of the method should change to IEnumerable<Information>

instead Information

.

+2


source


There is a more readable way of writing your query (which 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();
}

      

0


source







All Articles