我希望能够做的是构建一个LINQ查询,当其中一个字段发生变化时,它会从某些DataRows中检索一些值.这是一个人为的例子来说明:
Observation Temp Time
------------- ---- ------
Cloudy 15.0 3:00PM
Cloudy 16.5 4:00PM
Sunny 19.0 3:30PM
Sunny 19.5 3:15PM
Sunny 18.5 3:30PM
Partly Cloudy 16.5 3:20PM
Partly Cloudy 16.0 3:25PM
Cloudy 16.0 4:00PM
Sunny 17.5 3:45PM
Run Code Online (Sandbox Code Playgroud)
当观察从前一个观察发生变化时,我只想检索条目.所以结果将包括:
Cloudy 15.0 3:00PM
Sunny 19.0 3:30PM
Partly Cloudy 16.5 3:20PM
Cloudy 16.0 4:00PM
Sunny 17.5 3:45PM
Run Code Online (Sandbox Code Playgroud)
目前有代码迭代DataRows并进行结果的比较和构建,但希望使用LINQ来实现这一目标.
我想做的是这样的事情:
var weatherStuff = from row in ds.Tables[0].AsEnumerable()
where row.Field<string>("Observation") != weatherStuff.ElementAt(weatherStuff.Count() - 1) )
select row;
Run Code Online (Sandbox Code Playgroud)
但这不起作用 - 并且不会编译,因为它在声明之前尝试使用变量'weatherStuff'.
可以用LINQ做我想做的事吗?我在SO上没有看到像这样的另一个问题,但可能错过了它.
这是一个更普遍的想法,可能是相互影响.它比@tvanfosson发布的更复杂,但在某种程度上,我觉得它更优雅:-).您要执行的操作是使用第一个字段对观察结果进行分组,但是每次值更改时您都希望启动一个新组.然后,您要选择每个组的第一个元素.
这听起来几乎像LINQ,group by
但它有点不同,所以你不能真正使用标准group by
.但是,您可以编写自己的版本(这是LINQ的奇迹!).您可以编写自己的扩展方法(例如GroupByMoving
),也可以编写将类型更改IEnumerable
为某个接口的扩展方法,然后GroupBy
为此接口定义.生成的查询将如下所示:
var weatherStuff =
from row in ds.Tables[0].AsEnumerable().AsMoving()
group row by row.Field<string>("Observation") into g
select g.First();
Run Code Online (Sandbox Code Playgroud)
唯一剩下的就是定义AsMoving
和实施GroupBy
.这有点工作,但它通常是有用的东西,它也可以用来解决其他问题,所以它可能值得这样做:-).我的帖子的摘要是关于LINQ的好处是你可以自定义操作符的行为以获得非常优雅的代码.
我没有测试过,但实现应该如下所示:
// Interface & simple implementation so that we can change GroupBy
interface IMoving<T> : IEnumerable<T> { }
class WrappedMoving<T> : IMoving<T> {
public IEnumerable<T> Wrapped { get; set; }
public IEnumerator<T> GetEnumerator() {
return Wrapped.GetEnumerator();
}
public IEnumerator<T> GetEnumerator() {
return ((IEnumerable)Wrapped).GetEnumerator();
}
}
// Important bits:
static class MovingExtensions {
public static IMoving<T> AsMoving<T>(this IEnumerable<T> e) {
return new WrappedMoving<T> { 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<IEnumerable<T>> GroupBy<T, K>(this IEnumerable<T> source,
Func<T, K> keySelector) {
List<T> elementsSoFar = new List<T>();
IEnumerator<T> 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<T>();
}
elementsSoFar.Add(en.Current);
} while (en.MoveNext());
yield return elementsSoFar;
}
}
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
1793 次 |
最近记录: |