【问题标题】:LINQ two datatables joinLINQ 两个数据表连接
【发布时间】:2015-01-20 16:48:55
【问题描述】:

我被这个问题困住了。 我可以通过使用 foreach 来解决这个问题,但必须有更好的解决方案。

我有两个数据表。 首先有一个名为“Por”的列 第二个有两列名为“FirstPor”和“LastPor”。 我的目标是使用 LINQ 根据这样的条件创建新的数据表。

foreach ( DataRow row in FirstDatatable.Rows )
{
    foreach ( DataRow secondRow in SecondDatatable.Rows )
    {
       if ( row["Por"] >= secondRow["FirstPor"] && row["Por"] <= secondRow["LastPor"] )
            FinalDataTable.Rows.Add(row);
    }
}

我是 LINQ 的新手,这对我来说可能是个问题。我可以通过 Parallel.Foreach 做到这一点,但我认为 LINQ 可以更快。条件很简单。从第一个表(“Por”列)中获取每个数字,并检查它属于第二个表的哪一行(“Por”>=“FirstPor”&&“Por”


是的,我刚刚将并行代码修改为混合 LINQ/Parallel,看来我已经完成了。我使用了 James 和 Rahul 编写的内容并将其放入我的代码中。现在,这个过程需要 52 秒来估计 421 000 行:) 好多了。

public class Range
{
        public int FirstPor { get; set; }
        public int LastPor { get; set; }
        public int PackageId { get; set; }
}

var ranges = (from r in tmpDataTable.AsEnumerable()
          select new Range
                          {
                              FirstPor = Int32.Parse(r["FirstPor"] as string),
                              LastPor = Int32.Parse(r["LastPor"] as string),
                              PackageId = Int32.Parse(r["PackageId"] as string)
                          }).ToList();

Parallel.ForEach<DataRow>(dt.AsEnumerable(), row => 
{

int por = Int32.Parse(row["Por"].ToString());

                lock (locker)
                {
                    row["PackageId"] = ranges.First(range => por >= range.FirstPor && por <= range.LastPor).PackageId;
                }

                worker.ReportProgress(por);

            });

【问题讨论】:

  • 它的速度与它需要的一样快。除非你在谈论成千上万的行。在这种情况下,Linq 不会帮助您,但明智的多线程策略可能会。
  • 是的,我在邮局工作,所以有一个大数据。我的第一个数据表有大约 700 000 行,第二个表有大约 20 000 行,所以通常当我使用 Parallel.Foreach 时,我需要大约 7 分钟才能得到我的最终表。但我认为 LINQ 应该像 SQL 一样快。
  • 如果您正在谈论修改原始查询以防止这种内存连接,那么可能。您需要显示您的两个查询(或等效的、已清理的版本)并询问如何执行您的联接。
  • @Leeon82 Linq 只是 foreach 使用的相同机制的包装器,它使查询更容易编写,但不一定性能更好。我想知道您的逻辑是否最佳,因为您正在扫描第二个表中的每条记录以查找第一个表中的每条记录。
  • 我能够在查询开始前将所有字符串列转换为 int。

标签: c# linq join foreach datatable


【解决方案1】:

(前面有未经测试的代码.....)

var newRows = FirstDatatable.Rows
             .Where(row =>SecondDatatable.Rows
                 .Any(secondRow => row["Por"] >= secondRow["FirstPor"] 
                                && row["Por"] <= secondRow["LastPor"]);

FinalDataTable.Rows.AddRange(newRows);

但是,如果您真正关心的是速度,我的第一个建议是转储数据表并使用列表。我猜 SecondDatatable 基本上是固定的,并且可能每天变化不到一次。所以,少为此创建一个很好的内存结构:

class Range
{
     public int FirstPor {get; set;}
     public int LastPor {get; set;}
 }

 var ranges = (from r in SecondDatatable.Rows
               select new Range
                 { 
                     FirstPor = Int32.Parse(r["FirstPor"]),
                     LastPor = Int32.Parse(r["LastPor"])
                  }).ToList();

那么我们的代码就变成了:

var newRows = FirstDatatable.Rows
         .Where(row =>ranges
             .Any(range => row["Por"] >= range.FirstPor
                            && row["Por"] <= range.LastPor).ToList();

这本身应该会大大加快速度。

现在,如果成功,它将向上扫描范围,直到找到匹配的范围。如果失败,它必须在放弃之前扫描整个列表。所以,我们需要做的第一件事是加速这个过程,就是对范围列表进行排序。然后我们只需要扫描到范围的低端高于我们正在寻找的值。这应该会将那些超出任何范围的行的处理时间减少一半。

【讨论】:

  • 我想你就快到了,这对我来说似乎很清楚。我将在我的工作中尝试使用原始数据。因为每天邮局都会产生必须以多种方式分开的大数据。所以,我想弄清楚如何更快地管理流程。还是非常感谢
  • 我在考虑包含 SecondTable 范围的列表。如果我们使用某个范围(SeconTable)中的所有“Por”,那么这个范围将被删除。那么带范围的表格会越来越小。这是一个想法,尚未对此进行测试,但我想我已经在大学数学中遇到了这个解决方案:)
【解决方案2】:

试试这个:-

DataTable FinalDataTable = (from x in dt1.AsEnumerable()
                           from y in dt2.AsEnumerable()
                           where x.Field<int>("Por") >= y.Field<int>("FirstPor")
                                && x.Field<int>("Por") <= y.Field<int>("LastPor")
                           select x).CopyToDataTable();

这里是完整的Working Fiddle,(我已经使用您现有的代码和我的 LINQ 代码测试了一些示例数据)您可以将其复制粘贴到您的编辑器中并进行测试,因为 DotNet Fiddle 不支持 AsEnumerable。

【讨论】:

  • 好的,我试试。看来需要在LINQ语句之前将列转换为int。
  • @Leeon82 - 不,我们没有将列转换为int,Field&lt;T&gt; 只是提供对我们列的强类型访问,正如您在我的小提琴中看到的那样,我已经定义了列的数据类型同时定义哪个是好的做法。
猜你喜欢
  • 2014-01-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多