2014-12-30 83 views
0
class Bar 
{ 
    public DateTime Time { get; set; } 
    public double Price { get; set; } 
} 

class Instrument 
{ 
    public List<Bar> Bars { get; set; } 
    public string Name { get; set; } 

    public Instrument(string name, string path) { 
     // set the Bars list here reading from files 
    } 
} 

以下是我的两个简化版本。我正在为货币创建一个自定义的回测平台。目前的问题是在每台仪器上没有价格数据的地方切断酒吧。Linq列表清单

我从XML文件读取价格。

var xlinqBarLists = xlinqInstruments.Select(i => i.Bars); 

这基本上是

List<List<Bar>> xlinqBarLists 

通过每个单独列表我想要做的就是循环,找到最新的开始日期和最早结束日期,然后砍掉那个时间窗口外的所有酒吧。我的黑客攻击代码是

var xlinqInstruments = root.Elements("instrument").Select(a => 
    new Instrument(a.Element("name").Value, a.Element("path").Value));  

var xlinqBarLists = xlinqInstruments.Select(i => i.Bars); 

DateTime latestStartDate = DateTime.MinValue; 
DateTime earliestEndDate = DateTime.MaxValue; 

foreach (List<Bar> bars in xlinqBarLists) 
{ 
    if (bars.Min(b => b.Time) > latestStartDate) 
     latestStartDate = bars.Min(b => b.Time); 

    if (bars.Max(b => b.Time) < earliestEndDate) 
     earliestEndDate = bars.Max(b => b.Time); 
} 

foreach (List<Bar> barList in xlinqBarLists) 
{ 
    var timeWindowBars = from bar in barList 
        where bar.Time >= latestStartDate && bar.Time <= earliestEndDate 
        select bar; 

    // I need some way to overwrite the original Instrument.Bars property with timeWindowBars 
    // Suggestions? 
} 

我可以通过跳过foreach循环更快速高效地执行此操作吗?

+1

这应该属于代码审查:http://codereview.stackexchange.com/ –

+0

你是否想要将每个乐器的'Bars'属性设置为'List ''只包含那些属于mi所有*'Bar'对象(包括其他'Instrument's上的对象)的最小结束日期和最大开始日期? –

回答

0

有关最新的开始日期和最早结束日期,您可以使用

DateTime latestStartDate = xlinqInstruments.Max(i => i.Bars.Min(bar => bar.Time)); 
DateTime earliestEndDate = xlinqInstruments.Min(i => i.Bars.Max(bar => bar.Time)); 

而对于最后一部分也许你想添加一个参数的构造函数用于'Instrument'然后

var result = xlinqInstruments 
       .Select(i=>new Instrument() 
            { 
             Name = i.Name, 
             Bars = i.Bars.Where(bar => bar.Time >= latestStartDate 
                   && bar.Time <=earliestEndDate) 
                .ToList() 
            }); 
+0

它工作出色。感谢这样一个优雅简单的解决方案。我知道所有这些循环让我的生活变得不必要的复杂。 –

-1

呼叫ToList分配给xlinqBarLists前:

var xlinqBarLists = xlinqInstruments.Select(i => i.Bars).ToList(); 

否则你一遍又一遍解析相同的XML。

如果您想稍后更新它们,那么在创建xlinqInstruments时最好也应该调用ToList

+2

请注意解释投票吗? – MarcinJuraszek

+0

这不是我... –

0

这是一个答案,如果my comment above,(我已经复制/粘贴下面)证明是这样的。

你想每个仪器的酒吧属性设置为仅包含那些属于最低 结束日期和最大的开始日期在所有酒吧对象中的对象一个 列表(包括 那些存在于其他仪器) ?

// Get the value of the earliest Bar.Time on each Instrument, and select the most recent of those. 
DateTime latestStartDate = xlinqInstruments.Max(instrument => instrument.Bars.Min(bar => bar.Time)); 

// Get the value of the latest Bar.Time on each Instrument, and select the earliest of those. 
DateTime earliestEndDate = xlinqInstruments.Min(instrument => instrument.Bars.Max(bar => bar.Time)); 

// Overwrite the Bars collection of each instrument with its contents truncated appropriately. 
// I'd suggest doing this with a foreach loop as opposed to what I've provided below, but that's just me. 
xlinqInstruments.ForEach(instrument => 
{ 
    instrument.Bars = instrument.Bars.Where(obj => obj.Time >= latestStartDate && obj.Time <= earliestEndDate).ToList(); 
}); 

这可能是一文不值的ForEach方法需要你先在xlinqInstruments收集调用.ToList()。在我的代码中,我假设该集合已经实现到List<Instrument>

您可能也有兴趣linq的Enumerable.SelectMany方法。

Enumerable.SelectMany方法(IEnumerable的,Func键>)

项目的序列中的每个元素到IEnumerable和结果序列合并为一个序列。

+0

感谢约书亚花时间回答。 –