Linq查询问题

时间:2011-03-05 14:53:11

标签: c# .net linq

有一些标准方法来计算符合某些条件的元素数量:

collection.Where(d=> d==something).Count();

我需要以下功能(伪鳕鱼):

collection.Where(d=> (d==something) && (d.Next == somethingElse)).Count();

编辑:d.Next - 是集合中d之后的下一个元素。

如何实现这一目标?

5 个答案:

答案 0 :(得分:5)

假设你所拥有的是一个涉及源序列中连续元素的谓词,你可以这样做:

int numMatches = collection.Zip(collection.Skip(1), (prev, next) =>
                                prev == something && next == somethingElse)
                           .Count(match => match)

在应用过滤器之前,这会将序列叠加在序列的一个延迟版本上。

答案 1 :(得分:3)

var result = collection.Count(d => 
     d == something && 
     d.Next == somethingElse
);
如果d.Next属性为d或序列中的下一个元素,则

编辑

var result = collection.Zip(
    collection.Skip(1),
    (first, second) => first == something && second == somethingElse
).Count(i => i);

答案 2 :(得分:1)

您可以编写一个新的运算符(假设Linq-to-objects),使用枚举器明确地检查它。

<强>代码:

public static partial class Enumerable
{
    public static IEnumerable<TSource> WhereNext<TSource> (this IEnumerable<TSource> source, Func<TSource, bool> predicate, TSource next)
    {
        if (source == null)
            throw new ArgumentNullException("source");
        if (predicate == null)
            throw new ArgumentNullException("predicate");

        return WhereNextImpl(source, predicate, next);
    }

    private static IEnumerable<TSource> WhereNextImpl<TSource>(IEnumerable<TSource> source, Func<TSource, bool> predicate, TSource next)
    {
        using (var enumerator = source.GetEnumerator())
        {
            TSource current;
            TSource nextElement;

            if (!enumerator.MoveNext())
                yield break;
            while (true)
            {
                current = enumerator.Current;
                if (!enumerator.MoveNext())
                    yield break;
                nextElement = enumerator.Current;

                if (predicate(current) && EqualityComparer<TSource>.Default.Equals(next, nextElement))
                    yield return current;
            }
        }
    }
}

警告:目前使用EqualityComparer<TSource>.Default进行比较。应该完成另一个使用自定义比较器的实现。

答案 3 :(得分:1)

如果收集是stirng的列表,你可以尝试像

这样的东西
var selectC = from c in collection
let nextC = collection.IndexOf(c) == collection.Count - 1 ? null : collection[collection.IndexOf(c) + 1]
where string.IsNullOrEmpty(c) && string.IsNullOrEmpty(nextC)
select c;

涉及let的查询很难转化为方法链但我从Resharper的自动转换得到了这个

var selectC =
    collection.Select(
        c =>
        new {c, nextC = collection.IndexOf(c) == collection.Count - 1 ? null : collection[collection.IndexOf(c) + 1]}).
        Where(@t => string.IsNullOrEmpty(@t.c) && string.IsNullOrEmpty(@t.nextC)).Select(@t => @t.c);

答案 4 :(得分:1)

您可以使用Aggregate Method创建自定义总和:

var result = collection.Aggregate(
    Tuple.Create(false, 0),
    (s, x) => Tuple.Create(x == something,
                           s.Item1 + (s.Item0 && (x == somethingElse) ? 1 : 0)),
    s => s.Item1);

它的工作原理如下:

Item            Accumulator
--------------- ---------------
                (false, 0)
foo             (false, 0)
something       (true, 0)
bar             (false, 0)
something       (true, 0)
somethingElse   (false, 1)
somethingElse   (false, 1)
baz             (false, 1)
                ---------------
                Result: 1