2013-04-09 38 views
2

我有三個長度相等的不同List<string>,它們包含不同類型的數據。例如:使用lambda函數合併包含不同對象的列表

List<string> dates = new List<string>() { "20120301", "20120401", "20120501", "20120601", "20120701"}; 
List<string> times = new List<string>() { "0500", "0800", "0100", "1800", "2100" }; 
List<string> quantities = new List<string>() { "1", "2", "1", "3", "1" }; 

實際數據可能是任何東西,但列表總是具有相同的長度。我想將它們合併成一個List<DTQ>

public struct DTQ 
{ 
    DateTime dt; 
    double q; 
    public DTQ(DateTime dt, double q) { this.dt = dt; this.q = q; } 
} 

有沒有辦法用lambda函數做到這一點?到目前爲止,我已經成功地創建一個描述我會怎樣,如果它是三個strings代替List<string> S中的數據映射lambda函數:

Func<string, string, string, DTQ> mergeFields = (d, t, q) 
      => new DTQ(DateTime.ParseExact(string.Format("{0}{1}", d, t), "yyyyMMddhhmm", CultureInfo.InvariantCulture), double.Parse(q)); 

我不知道在那裏我可以從那裏,雖然。這個想法是將這個函數應用到列表的每個索引。

+0

你想怎麼映射呢? – Romoku 2013-04-09 17:45:12

+0

第一項應該是(2012年3月1日05:00,1)。第二項應該是(2012年4月1日08:00,2)。等等,爲五個條目。 – Otaia 2013-04-09 17:49:42

回答

3

看起來像Zip工作,除非你有3個名單,而不是2

使用當前的mergeFields定義,你可以做這樣的事情:

var dateAndTimes = dates.Zip(times, (d, t) => new { Date = d, Time = t }); 
var all = dateAndTimes.Zip(quantities, (dt, q) => new { dt.Date, dt.Time, Quantity = q }); 
var result = all.Select(x => mergeFields(x.Date, x.Time, x.Quantity)).ToList(); 

如果你想有一個更通用的解決方案,你也可以創建Zip的重載需要3個類別:

public static IEnumerable<TResult> Zip<TFirst, TSecond, TThird, TResult>(
    this IEnumerable<TFirst> first, 
    IEnumerable<TSecond> second, 
    IEnumerable<TThird> third, 
    Func<TFirst, TSecond, TThird, TResult> resultSelector) 
{ 
    return first.Zip(second, (f, s) => new { f, s }) 
       .Zip(third, (fs, t) => resultSelector(fs.f, fs.s, t)); 
} 

(alternati vely,您可以使用Romoku的實現是可能的快一點)

,然後用它是這樣的:

var result = dates.Zip(times, quantities, mergeFields).ToList(); 
+0

好的答案!從未見過Zip在行動;) – 2013-04-09 17:59:46

+0

太棒了,這工作得很好。我會嘗試其他的答案,但我不知道我是否需要它,因爲我只需要在我的代碼中的一個地方使用它。 – Otaia 2013-04-09 18:09:22

2

你可以做雙拉鍊但效率不高。這是一個擴展方法來壓縮三個枚舉。

public static class EnumerableExtensions 
{ 
    public static IEnumerable<TResult> Zip<TFirst, TSecond, TThird, TResult>(
     this IEnumerable<TFirst> first, 
     IEnumerable<TSecond> second, 
     IEnumerable<TThird> third, 
     Func<TFirst, TSecond, TThird, TResult> resultSelector) 
    { 
     if(first == null) 
      throw new ArgumentNullException("first cannot be null"); 
     if(second == null) 
      throw new ArgumentNullException("second cannot be null"); 
     if(third == null) 
      throw new ArgumentNullException("third cannot be null"); 
     if(resultSelector == null) 
      throw new ArgumentNullException("resultSelector cannot be null"); 

     using (var iterator1 = first.GetEnumerator()) 
     using (var iterator2 = second.GetEnumerator()) 
     using (var iterator3 = third.GetEnumerator()) 
     { 
      while (iterator1.MoveNext() && iterator2.MoveNext() && iterator3.MoveNext()) 
      { 
       yield return resultSelector(
        iterator1.Current, 
        iterator2.Current, 
        iterator3.Current); 
      } 
     } 
    } 
} 

用法:

var result = dates.Zip(times, quantities, mergeFields); 
+0

你爲什麼說這是「低效率」?你有分析過嗎?顯然你的解決方案更有效率,但我不認爲這是一個非常明顯的區別... – 2013-04-09 18:02:56

+0

@ThomasLevesque這兩個zip解決方案需要一箇中間對象來保存結果。 – Romoku 2013-04-09 18:03:49

+0

是的,但差異可能不是那麼大......無論如何,+1因爲嚴格來說,您的實施可能會更好;) – 2013-04-09 18:06:45