【问题标题】:Use LINQ to populate a single list from two other lists使用 LINQ 从其他两个列表填充单个列表
【发布时间】:2012-09-19 14:08:23
【问题描述】:

现在,我有 2 个列表(_pumpOneSpm 和 _pumpTwoSpm),它们是数据库查询的结果。现在,我一直在使用 LINQ 填充列表以供我使用以进行计算。类似的东西:

var spmOne = _pumpOneSpm.Where((t, i) => _date[i].Equals(date) &&
            DateTime.Compare(_time[i], DateTime.Parse(start)) > 0 && 
            DateTime.Compare(_time[i], DateTime.Parse(end)) < 0).ToList();

这很好,因为我一直在从一个列表中提取数据以将特定数据添加到另一个列表中。但是现在,我需要从两个列表中提取数据以添加到一个列表中。我很好奇是否有办法用 LINQ 做到这一点,或者我是否应该使用 for 循环进行迭代?这是我使用 for 循环得到的:

        for (var i = 0; i < _pumpOneSpm.Count; i++)
        {
            if (_date[i].Equals(date))
            {
                if (DateTime.Compare(_time[i], DateTime.Parse(start)) > 0)
                {
                    if (DateTime.Compare(_time[i], DateTime.Parse(end)) < 0)
                    {
                        spmOne.Add(_pumpOneSpm[i]);
                        spmOne.Add(_pumpTwoSpm[i]);
                    }
                }
            }
        }

这行得通,可以做我想做的事。但我只是想让它更有效率和更快。我可以为每个列表使用类似于第一个代码块的两行代码,但这意味着我要迭代两次。所以,重申我的问题,是否可以使用 LINQ 命令同时从两个列表中提取数据以填充另一个列表,或者我应该坚持我的 for 循环?感谢您的所有帮助。

编辑

我没有提到,利用这些步骤的函数的目的是微调 _pumpOneSpm 和 _pumpTwoSpm 的 MAX。不是每个的最大值,而是它们之间的最大值。因此,最初我将它们添加到一个列表中,然后调用 spmOne.Max()。但是对于像上面这样的两个 LINQ 查询,我正在运行一个 if 语句来比较两个最大值,然后返回两者中的较大者。所以,从技术上讲,它们不需要在一个列表中,我只是认为如果它们存在会更容易处理。

【问题讨论】:

    标签: c# linq list


    【解决方案1】:

    所以最简单的方法是这样的:

    var resultList = list1.Concat(list2).ToList();
    

    请注意,这将与您的 for 循环略有不同(项目的顺序不会相同)。它将包含一个列表中的所有项目,然后是另一个列表中的所有项目,而不是第一个列表中的第一个,第二个中的第一个,等等。如果这很重要,您仍然可以使用 LINQ 来完成,但它需要一些额外的方法调用。

    您提到了性能;值得注意的是,在性能方面,您不会比for 循环好得多。你可以得到更短的代码;更具可读性的代码,并且将执行大致相同。尽管就运行速度而言,根本没有进一步改进的余地。

    另外值得注意的是,你可以将这两种方法结合起来;这甚至不是一个坏主意。您可以使用 LINQ 过滤两个输入序列(使用 Where),然后在结果上使用 foreach 将它们添加到列表中(或使用 AddRange)。

    var query1 = _pumpOneSpm.Where((t, i) => _date[i].Equals(date) &&
                DateTime.Compare(_time[i], DateTime.Parse(start)) > 0 && 
                DateTime.Compare(_time[i], DateTime.Parse(end)) < 0);
    var query2 = ...
    List<T> results = new List<T>(query1);
    results.AddRange(query2);
    

    【讨论】:

    • 感谢您的回答。 concat() 会起作用,因为我并不真正担心列表的顺序。 union() 也可以,因为我也不担心重复。我编辑了我的原始帖子,添加了更多信息,直到阅读您的答案后才添加。
    【解决方案2】:

    所以,重申一下我的问题,是否可以使用 LINQ 命令来 同时从两个列表中提取数据以填充另一个列表,或者 我应该坚持我的 for 循环吗?

    合并列表:

    var mergedList = list1.Union(list2).ToList();
    

    如果你愿意,可以选择过滤:

    var filtered = mergedList.Where( p => ... filter ... );
    

    对于 Max:

    var max = filtered.Max();
    

    注意:

    正如 OP 所说,订单不需要不重复,所以 Union 就可以了。

    【讨论】:

    • 联合是一个集合操作,也会在结果中执行Distinct
    • 感谢您的回答。 concat() 会起作用,因为我并不真正担心列表的顺序。 union() 也可以,因为我也不担心重复。我编辑了我的原始帖子,添加了更多信息,直到阅读您的答案后才添加。
    • 您很可能希望在合并之前进行过滤,因为过滤器取决于每个元素的索引。
    • @RiskyMartin:我为什么要过滤?我不在乎重复或订单,或者任何与此相关的事情。我只是在寻找两个列表之间的最高数字。
    • @Randolf 因为 OP 正在过滤列表。
    【解决方案3】:

    你可以使用 SelectMany 方法

    http://msdn.microsoft.com/en-us/library/bb548748.aspx

    【讨论】:

      【解决方案4】:

      您可以使用Enumerable.Range 实现与for 循环类似的功能。 SelectMany 然后允许您在每次迭代时添加多个项目,然后将结果序列展平。

      spmOne = Enumerable
                   .Range(0, _pumpOneSpm.Count)
                   .Where(index => _date[index].Equals(date) &&
                           DateTime.Compare(_time[index], DateTime.Parse(start)) > 0 &&
                           DateTime.Compare(_time[index], DateTime.Parse(end)) < 0)
                   .SelectMany(index => new [] { _pumpOneSpm[index], _pumpTwoSpm[index] })
                   .ToList();
      

      这里是查询语法版本:

      spmOne = (from index in Enumerable.Range(0, _pumpOneSpm.Count)
                where _date[index].Equals(date) &&
                      DateTime.Compare(_time[index], DateTime.Parse(start)) > 0 &&
                      DateTime.Compare(_time[index], DateTime.Parse(end)) < 0
                from pumpSpm in new [] { _pumpOneSpm[index], _pumpTwoSpm[index] }
                select pumpSpm).ToList();
      

      【讨论】:

        【解决方案5】:

        如果你想避免使用索引,你可以Zip 一起使用。

        spmOne = _pumpOneSpm
                  .Zip(_pumpTwoSpm, (pump1, pump2) => new { pump1, pump2 } )
                  .Zip(_date, (x, pumpDate) => new { x.pump1, x.pump2, date = pumpDate })
                  .Zip(_time, (x, time) => new { x.pump1, x.pump2, x.date, time })
                  .Where(x => x.date.Equals(date) &&
                              DateTime.Compare(x.time, DateTime.Parse(start)) > 0 &&
                              DateTime.Compare(x.time, DateTime.Parse(end)) < 0)
                  .SelectMany(x => new [] { x.pump1, x.pump2 })
                  .ToList();
        

        在功能上有一个小的区别:如果任何序列短于_pumpOneSpm,则生成的序列将是最短序列的长度,并且不会因索引超出范围而引发异常。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2013-06-15
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2017-09-28
          • 1970-01-01
          相关资源
          最近更新 更多