0

I have a list of dates for periods. In 1 element of this list there is two variables: startDate and endDate. The problem I am facing is that the endDate represents the endDate of the previous element, the startDate represents the current element's start date.

Originally my check looked like this:

if(dateList.Any(d => DateTime.Now > d.startDate && DateTime.Now < d.endDate))
{
    // Do something
}

Is there a way to access the previous element in this Any() function?

jaredbaszler
  • 3,941
  • 2
  • 32
  • 40
LMG
  • 91
  • 1
  • 6
  • As I understand from your data, you've got a class with 2 fields or properties Start and End for dates? – Roman Zeleniy Nov 29 '19 at 16:53
  • You'd have to do a little bit more modifications e.g. --> `Enumerable.Range(0, dateList.Count-1).Any(i =>DateTime.Now > dateList[i+1].startDate && DateTime.Now < dateList[i].endDate)`. take this with caution as I've not tested the code but visually it seems valid to me atleast. – Ousmane D. Nov 29 '19 at 16:56
  • 1
    It'd be best to iterate through the `dateList`; perhaps a for loop, or a foreach and updating a previousItem variable per iteration. – Mark Cilia Vincenti Nov 29 '19 at 16:57
  • Just convert `dateList` into a list of items that have the right startdate and enddate in one item. – Gert Arnold Nov 29 '19 at 18:04
  • You may find this useful: [Get previous and next item in a IEnumerable using LINQ](https://stackoverflow.com/questions/8759849/get-previous-and-next-item-in-a-ienumerable-using-linq/58778597#58778597) – Theodor Zoulias Dec 09 '19 at 18:34

4 Answers4

3

The .Any() method is really just a fancy shortform here for:

foreach (var date in dateList)
{
    if (DateTime.Now > date.StartDate && DateTime.Now < date.EndDate)
    {
        // Do something
        break;
    }
}

So functionally you could just write your own iterator method to do this and it would only be a couple more lines of code:

Date previousDate = null;

foreach (var date in dateList) // using foreach works with any enumerable type
{
    if (DateTime.Now > date.StartDate && DateTime.Now < date.EndDate)
    {
        if (previousDate != null)
        {
            // Do something
        }

        break;
    }

    previousDate = date;
}

If you do this often and want a cleaner extension method to help you do this with less code, you can use something like Jon Skeet's answer here:

Calculate difference from previous item with LINQ

Trevor Elliott
  • 11,292
  • 11
  • 63
  • 102
0

There's a library called MoreLinq that has some handy extension methods, and includes a PairWise extension method that does what you want.

In this example I have pasted the method directly in:

class Program
{
    static void Main()
    {
        var dateList = new List<Item>
        {
            new Item {startDate = DateTime.Now.AddDays(1)},
            new Item {startDate = DateTime.Now.AddDays(-4)},
            new Item {startDate = DateTime.Now.AddDays(-5)}
        };

        if (dateList
            .Pairwise((previous, current) => DateTime.Now > current.startDate && DateTime.Now < previous.startDate)
            .Any(b => b))
        {
            // Do something

        }
    }
}

class Item
{
    public DateTime startDate;
}

static class EnumerableExtensions
{
    public static IEnumerable<TResult> Pairwise<TSource, TResult>(this IEnumerable<TSource> source, Func<TSource, TSource, TResult> resultSelector)
    {
        if (source == null) throw new ArgumentNullException(nameof(source));
        if (resultSelector == null) throw new ArgumentNullException(nameof(resultSelector));

        return _(); IEnumerable<TResult> _()
        {
            using var e = source.GetEnumerator();

            if (!e.MoveNext())
                yield break;

            var previous = e.Current;
            while (e.MoveNext())
            {
                yield return resultSelector(previous, e.Current);
                previous = e.Current;
            }
        }
    }
}
Stuart
  • 5,358
  • 19
  • 28
0
public class Dates
{
    public DateTime StartDate { get; set; }
    public DateTime EndDate { get; set; }

}



        static void Main(string[] args)
    {
        var ourList = new List<Dates>();
        ourList.Add(new Dates {EndDate = DateTime.MinValue, StartDate = new DateTime(2019, 07, 28, 22, 35, 5,
            new CultureInfo("en-US", false).Calendar)
        });

        ourList.Add(new Dates {EndDate = new DateTime(2019, 07, 28, 23, 35, 5, new CultureInfo("en-US", false).Calendar), StartDate = new DateTime(2019, 07, 29, 22, 35, 5,
            new CultureInfo("en-US", false).Calendar)
        });

        ourList.Add(new Dates
        {
            EndDate = new DateTime(2019, 08, 28, 23, 35, 5, new CultureInfo("en-US", false).Calendar),
            StartDate = new DateTime(2019, 07, 29, 22, 35, 5,
new CultureInfo("en-US", false).Calendar)
        });

        ourList.OrderBy(zx => zx.EndDate);
        var listOfWrongDates = ourList.Where(zy => zy.StartDate < DateTime.Now &&
            ourList.IndexOf(zy) - 1 >= 0 ? ourList.ElementAt((ourList.IndexOf(zy) - 1)).EndDate > DateTime.Now : false);

        Console.WriteLine("Hello World!");
    }
0

As there is no built-in function, you would have to write your own lambda expression.

Identify at which position your current element resides in the list, then look at the previous position (if greater zero):

dateList.Any(current =>
{
    var currentIndex = dateList.IndexOf(current); // get index of current element

    if(currentIndex > 0) // if current element is not first
    {
        var previous = dateList[currentIndex - 1]; // get previous element

        if (DateTime.Now > current.startDate && DateTime.Now < previous.endDate)
        {
            return true;
        }
    }

    return false;
});
Kai Hartmann
  • 3,106
  • 1
  • 31
  • 45
  • 1
    IndexOf is not a function of Linq, it's based on `Array.IndexOf` and only works with Arrays and Lists. So it won't work in a case where you're working with an IEnumerable. It also will needlessly perform poorly with large lists as it has to enumerate through the array to find the matching value of the previous item on every iteration. https://referencesource.microsoft.com/#mscorlib/system/array.cs – Trevor Elliott Dec 09 '19 at 15:18