Reputation: 3102
There is standard way to count number of elements which fit some 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 this can be achieved?
Upvotes: 3
Views: 147
Reputation: 61497
You can write a new operator (assuming Linq-to-objects) that checks this using the enumerator explicitly.
Code:
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;
}
}
}
}
Caveat: Currently uses EqualityComparer<TSource>.Default
for comparision. Another implementation with a custom comparer should be done.
Upvotes: 1
Reputation: 217411
You can use the Aggregate Method to create a custom sum:
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 like this:
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
Upvotes: 1
Reputation: 32343
var result = collection.Count(d =>
d == something &&
d.Next == somethingElse
);
EDIT: in the case if d.Next
a property of d
or the next element in the sequence:
var result = collection.Zip(
collection.Skip(1),
(first, second) => first == something && second == somethingElse
).Count(i => i);
Upvotes: 3
Reputation: 113472
Assuming that what you have is a predicate that involves consecutive elements in the source-sequence, you can do:
int numMatches = collection.Zip(collection.Skip(1), (prev, next) =>
prev == something && next == somethingElse)
.Count(match => match)
This overlays the sequence on a one-deferred version of the sequence before applying the filter.
Upvotes: 5
Reputation: 109027
if collection were List of stirng, you could try something like
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 tricky to translate into method chain 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);
Upvotes: 1