Question on Linq Query

There is a standard way to count the number of elements that match a condition:

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

I need the following functionality (pseudo-cod):

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

EDIT: d.Next is the next element after d in the collection.

How can this be achieved?

+3
source share
5 answers

Assuming you have a predicate that includes sequential elements in a source sequence, you can do:

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

This is a sequence overlay on a single task version of the sequence before applying the filter.

+5
source
var result = collection.Count(d => 
     d == something && 
     d.Next == somethingElse
);

EDIT: in case the d.Nextproperty dor the next element in the sequence:

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

( 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 . .

+1

List of 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;

queries involving let are difficult to translate into a chain of methods, but I got this from Resharper's automatic conversion

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);
+1
source

You can use the Aggregate Method to create a custom amount:

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

It works as follows:

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
+1
source

Source: https://habr.com/ru/post/1796503/


All Articles