筛选比较同一集合的两个元素的 lambda 表达式

本文关键字:两个 元素 表达式 lambda 比较 集合 筛选 | 更新日期: 2023-09-27 18:02:05

我想知道是否可以为 Linq 扩展(或自定义扩展(编写一个表达式,以使用比较集合的两个元素的 lambda 表达式来过滤集合。

换句话说,如果我有一个List<DateTime>和一些值,var v = DateTime.Today,那么我想知道是否可以编写创建一个方法,该方法将返回集合中小于或等于值的第一个元素,current <= v,集合的下一个元素大于或等于该值, next >= v .

请注意,以上只是一个示例,可能是也可能不是最终实现。


如果.First()方法接受Func<DateTime, DateTime, bool>,两个DateTime参数是序列的连续元素,则以下方法将是一个有效的解决方案:

dateCollection.First((current, next) => current <= v && next >= v);

另请注意,对于给出的示例,有效的解决方法可能是使用 .OrderBy,然后找到大于 d 的第一个索引并减去 1 。但是,这种类型的比较并不是我正在寻找的唯一比较。我可能遇到这样一种情况:我正在检查第一种情况的List<string>,其中current元素以我的值的第一个字母开头,vnext元素以我的值的最后一个字母v结尾。


我正在寻找一些只是一些代码的东西。我的目标是找到最简单的解决方案,因此简洁很重要。

我正在寻找的是以下形式:

public static T First (...)
{
    ...
}

我相信这也需要两个或多个 lambda 表达式作为参数。同样可能提供良好解决方案的一件事是能够选择序列中所有可能的连续元素对,并调用.First()方法。

例如:

//value 
var v = 5;
//if my collection is the following
List<int> stuff = { a, b, c, d };
//select into consecutive pairs, giving: 
var pairs = ... // { { a, b }, { b, c }, { c, d } };
//then run comparison
pairs.First(p => p[0] <= v && p[1] >= v).Select(p => p[0]);


谢谢,编码愉快! :)

筛选比较同一集合的两个元素的 lambda 表达式

我们可以

创建的是一个Pairwise方法,它可以将一系列值映射到表示每个值及其前面的值的对序列中。

public static IEnumerable<Tuple<T, T>> Pairwise<T>(this IEnumerable<T> source)
{
    using (var iterator = source.GetEnumerator())
    {
        if (!iterator.MoveNext())
            yield break;
        T prev = iterator.Current;
        while (iterator.MoveNext())
        {
            yield return Tuple.Create(prev, iterator.Current);
            prev = iterator.Current;
        }
    }
}

现在我们可以写出来:

var item = data.Pairwise()
    .First(pair => pair.Item1 <= v && pair.Item2 >= v)
    .Item1;

如果您要使用相当多的东西,则可能值得创建一个新的自定义类型来替换Tuple,以便您可以拥有CurrentNext属性,而不是Item1Item2

    List<int> list = new List<int>();
    list.Add(3);
    list.Add(2);
    list.Add(8);
    list.Add(1);
    list.Add(4);
    var element = list
         .Where((elem, idx) => idx < list.Count-1 && elem<=list[idx+1])
         .FirstOrDefault();
    Console.WriteLine(element);

苏尔特: 2

其中"elem"是当前元素

,"idx"是当前元素的索引

不确定您要在此处返回的内容是我的主要问题,但是以您的示例并将其放入 LINQ 语句中,它将如下所示:

DateTime? Firstmatch = dateCollection.DefaultIfEmpty(null).FirstOrDefault(a => a <= d && ((dateCollection.IndexOf(a) + 1) < (dateCollection.Count) && dateCollection[dateCollection.IndexOf(a) + 1] >= d));

严格按照描述,您可以组合 linq 和列表索引以查找与您的标准匹配的第一个索引,并返回其元素:

DateTime d= DateTime.Today;
var res = dateCollection[Enumerable.Range(0, dateCollection.Count - 1).First(i => dateCollection[i] <= d && dateCollection[i + 1] >= d)];

Servy的答案可以在没有扩展方法的情况下处理:

var first = items
  .Select((current, index) => index > 0 ? new { Prev = items.ElementAt(index-1), Current = current } : null)
  .First(pair => pair != null && pair.Prev <= v && pair.Current >= v)
  .Prev;