使用lambda函数合并包含不同对象的列表
我有三个长度相等的不同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));
我不知道在那里我可以从那里,虽然。这个想法是将这个函数应用到列表的每个索引。
看起来像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();
好的答案!从未见过Zip在行动;) – 2013-04-09 17:59:46
太棒了,这工作得很好。我会尝试其他的答案,但我不知道我是否需要它,因为我只需要在我的代码中的一个地方使用它。 – Otaia 2013-04-09 18:09:22
你可以做双拉链但效率不高。这是一个扩展方法来压缩三个枚举。
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);
你为什么说这是“低效率”?你有分析过吗?显然你的解决方案更有效率,但我不认为这是一个非常明显的区别... – 2013-04-09 18:02:56
@ThomasLevesque这两个zip解决方案需要一个中间对象来保存结果。 – Romoku 2013-04-09 18:03:49
是的,但差异可能不是那么大......无论如何,+1因为严格来说,您的实施可能会更好;) – 2013-04-09 18:06:45
你想怎么映射呢? – Romoku 2013-04-09 17:45:12
第一项应该是(2012年3月1日05:00,1)。第二项应该是(2012年4月1日08:00,2)。等等,为五个条目。 – Otaia 2013-04-09 17:49:42