What I\'d like to be able to do is construct a LINQ query that retrieved me a few values from some DataRows when one of the fields changes. Here\'s a contrived example to illus
Here is one more general thought that may be intereting. It's more complicated than what @tvanfosson posted, but in a way, it's more elegant I think :-). The operation you want to do is to group your observations using the first field, but you want to start a new group each time the value changes. Then you want to select the first element of each group.
This sounds almost like LINQ's group by
but it is a bit different, so you can't really use standard group by
. However, you can write your own version (that's the wonder of LINQ!). You can either write your own extension method (e.g. GroupByMoving
) or you can write extension method that changes the type from IEnumerable
to some your interface and then define GroupBy
for this interface. The resulting query will look like this:
var weatherStuff =
from row in ds.Tables[0].AsEnumerable().AsMoving()
group row by row.Field("Observation") into g
select g.First();
The only thing that remains is to define AsMoving
and implement GroupBy
. This is a bit of work, but it is quite generally useful thing and it can be used to solve other problems too, so it may be worth doing it :-). The summary of my post is that the great thing about LINQ is that you can customize how the operators behave to get quite elegant code.
I haven't tested it, but the implementation should look like this:
// Interface & simple implementation so that we can change GroupBy
interface IMoving : IEnumerable { }
class WrappedMoving : IMoving {
public IEnumerable Wrapped { get; set; }
public IEnumerator GetEnumerator() {
return Wrapped.GetEnumerator();
}
public IEnumerator GetEnumerator() {
return ((IEnumerable)Wrapped).GetEnumerator();
}
}
// Important bits:
static class MovingExtensions {
public static IMoving AsMoving(this IEnumerable e) {
return new WrappedMoving { Wrapped = e };
}
// This is (an ugly & imperative) implementation of the
// group by as described earlier (you can probably implement it
// more nicely using other LINQ methods)
public static IEnumerable> GroupBy(this IEnumerable source,
Func keySelector) {
List elementsSoFar = new List();
IEnumerator en = source.GetEnumerator();
if (en.MoveNext()) {
K lastKey = keySelector(en.Current);
do {
K newKey = keySelector(en.Current);
if (newKey != lastKey) {
yield return elementsSoFar;
elementsSoFar = new List();
}
elementsSoFar.Add(en.Current);
} while (en.MoveNext());
yield return elementsSoFar;
}
}