【问题标题】:Merging lists containing different objects using lambda function使用 lambda 函数合并包含不同对象的列表
【发布时间】:2013-04-09 17:43:37
【问题描述】:

我有三个不同的List<string>s,长度相等,包含不同类型的数据。例如:

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&lt;DTQ&gt;

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

有没有办法用 lambda 函数做到这一点?到目前为止,我已经设法创建了一个 lambda 函数,该函数描述了如果数据是三个 strings 而不是 List&lt;string&gt;s,我将如何映射数据:

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));

不过,我不确定我能从那里去哪里。想法是将此函数应用于列表的每个索引。

【问题讨论】:

  • 你想如何映射它们?
  • 第一个条目应该是 (2012 Mar 01 05:00, 1)。第二个条目应该是 (2012 Apr 01 08:00, 2)。以此类推,共五个条目。

标签: c# list function lambda


【解决方案1】:

看起来像 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();

如果您想要更通用的解决方案,您还可以创建一个需要 3 个集合的 Zip 重载:

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));
}

(或者,您可以使用 Romoku 的实现,它可能会快一点)

然后像这样使用它:

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

【讨论】:

  • 不错的答案!从来没有见过 Zip 在行动 ;)
  • 太棒了,这工作得很好。我会尝试另一个答案,但我不知道我是否需要它,因为我只需要在我的代码中的一个地方使用它。
【解决方案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);

【讨论】:

  • 为什么说它“低效”?你剖析过吗?显然您的解决方案更有效,但我认为它不会产生非常明显的差异......
  • @ThomasLevesque 两个 zip 解决方案需要一个中间对象来保存结果。
  • 是的,但差异可能不是那么大...无论如何,+1 因为严格来说,您的实现可能更好;)
  • 重复答案? Thomas 已经提供了一些相同的扩展方法。
  • @ThomasLevesque 假设我做对了,我的机器上有 175% 的差异。 Test Code
猜你喜欢
  • 2023-03-22
  • 2019-02-20
  • 2018-09-13
  • 2020-01-21
  • 2019-07-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-09-10
相关资源
最近更新 更多