如何为实现IEnumerable<IEnumerable<T>>的类实现GetEnumerator方法

3

背景: 我创建了一个通用的TimeSeries<T>类,应该实现IEnumerable<IEnumerable<T>>接口:

public interface ITimeSeries<T> : IEnumerable<IEnumerable<T>> 
{
    T[,] DataMatrix { get; }  

    DateTime[] DateTime { get; }

    string[] Variables { get; }
}

public class TimeSeries<T> : ITimeSeries<T>
{
    public IEnumerator<IEnumerable<T>> GetEnumerator()
    {...}

    IEnumerator IEnumerable.GetEnumerator()
    {
        return GetEnumerator();
    }
}
TimeSeries<T>类实际上是一个矩阵数据结构,其中每列代表不同的变量,每行代表一次观测。此外,还有一个额外的DateTime[]数组表示时间轴。
作为开始,我希望能够通过foreach循环逐个变量遍历TimeSeries<T>变量,也可以通过内部foreach循环遍历特定变量的所有观察结果,但实现IEnumerable接口的真正原因是获得所有由IEnumerable接口提供的LINQ功能,前提是我可以确保每个观测结果的DateTime关联保持完好无损。
那么问题来了:如何实现GetEnumerator方法来实现这一目标?

1
http://blog.slaks.net/2010/12/nested-iterators-part-1.html http://blog.slaks.net/2010/12/nested-iterators-part-2.html - SLaks
StackOverflow 上也可以查看这个答案。 - tweakch
2个回答

2

最简单的方法就是遍历每一行,返回每一行的值。我假设您按行主序存储,其中第一个维度是行,第二个维度是列。如果按列主序,请将下面的r和c翻转:

public IEnumerator<IEnumerable<T>> GetEnumerator()
{
    int rows = DataMatrix.GetLength(0);
    int cols = DataMatrix.GetLength(1);

     for(int r = 0; r < rows; r++)
     {
        T[] row = new T[cols]();

        for(int c = 0; c < cols; c++)
        {
            row[c] = DataMatrix[r,c];
        }
        yield return row;
    }
}

如果你想避免复制,你可以将其实现为ListListArrayArray(使用T[][]而不是T[,])。


我喜欢这个解决方案,但我的主要担忧之一是每行失去时间上下文以及无法按列进行过滤。然而,这个问题并不在于你的回答,而是在于我的类的设计。另外,使用T[,]而不是T[][]的原因是与代码中其他地方的本机代码互操作性有关,但还是谢谢你的建议。 - nswart
如果您的筛选条件不是返回数据的一部分(例如 timeSeries.Where(date<DateTime.Today())),那么使用 Linq 会遇到麻烦。Linq 并不适用于这种情况。 - D Stanley
我决定用一个结构体来封装类型为T的值,该结构体还包括变量名和日期时间戳。 - nswart

0
我决定添加一个结构体,它将每个值包装起来,并添加DateTime时间戳和Variable名称属性。GetEnumerator方法会产生一个包装值的列。
    public struct TSItem<T>
    {
        public string Variable { get; private set; }
        public DateTime Date { get; private set; }
        public T Value { get; private set; }
    }

    public IEnumerator<IEnumerable<TSItem<T>>> GetEnumerator()
    {
        int rows = DataMatrix.GetLength(0);
        int cols = DataMatrix.GetLength(1);

        for (int c = 0; c < cols; c++)
        {
            var col = new List<TSItem<T>>();

            for (int r = 0; r < rows; c++)
            {
                col.Add(new TSItem<T>(this.Variables[c], this.DateTime[r], 
                                DataMatrix[r, c]));
            }
            yield return col;
        }
    }

这可能不是最高效的解决方案,但在LINQ查询方面实现了我想要的功能。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接