2014-12-30 82 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

感謝約書亞花時間回答。 –