【问题标题】:Access previous element in Any()? LINQ C#访问 Any() 中的前一个元素? LINQ C#
【发布时间】:2019-11-29 16:48:15
【问题描述】:

我有一个时期的日期列表。在此列表的 1 个元素中,有两个变量:startDate 和 endDate。我面临的问题是endDate代表上一个元素的endDate,startDate代表当前元素的开始日期。

原来我的支票是这样的:

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

有没有办法访问这个Any()函数中的前一个元素?

【问题讨论】:

  • 我从您的数据中了解到,您有一个包含 2 个字段或属性 Start 和 End 日期的类?
  • 你必须做更多的修改,例如--> Enumerable.Range(0, dateList.Count-1).Any(i =&gt;DateTime.Now &gt; dateList[i+1].startDate &amp;&amp; DateTime.Now &lt; dateList[i].endDate)。请谨慎使用,因为我没有测试过代码,但在视觉上它至少对我来说似乎是有效的。
  • 最好遍历dateList;可能是一个 for 循环,或者一个 foreach 并在每次迭代时更新一个 previousItem 变量。
  • 只需将dateList 转换为在一个项目中具有正确开始日期和结束日期的项目列表。

标签: c# linq


【解决方案1】:

.Any() 方法在这里实际上只是一个花哨的缩写:

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

所以从功能上讲,您可以编写自己的迭代器方法来执行此操作,并且只需要多几行代码:

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;
}

如果您经常这样做并且想要一个更简洁的扩展方法来帮助您用更少的代码完成此操作,您可以在这里使用 Jon Skeet 的回答:

Calculate difference from previous item with LINQ

【讨论】:

  • 从技术上讲,Any() 不只是中断,它还返回一个布尔值。
  • 我的代码没有显示Any() 是如何工作的,而是如果Any() 方法不存在,他可能会如何写同样的东西。
【解决方案2】:

由于没有内置函数,您必须编写自己的 lambda 表达式。

确定当前元素在列表中的哪个位置,然后查看前一个位置(如果大于零):

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;
});

【讨论】:

  • IndexOf 不是 Linq 的函数,它基于 Array.IndexOf 并且仅适用于数组和列表。因此,在您使用 IEnumerable 的情况下它不起作用。对于大型列表,它也将不必要地表现不佳,因为它必须遍历数组以在每次迭代中找到前一个项目的匹配值。 referencesource.microsoft.com/#mscorlib/system/array.cs
【解决方案3】:

有一个名为 MoreLinq 的库,它有一些方便的扩展方法,并包含一个 PairWise 扩展方法,可以满足您的需求。

在本例中,我将方法直接粘贴到:

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;
            }
        }
    }
}

【讨论】:

    【解决方案4】:
    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!");
        }
    

    【讨论】:

      猜你喜欢
      • 2019-11-16
      • 1970-01-01
      • 2014-12-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-03-06
      • 2013-11-23
      相关资源
      最近更新 更多