簡體   English   中英

LINQ兩個數據表聯接

[英]LINQ two datatables join

我陷入這個問題。 我可以通過使用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” <=“ LastPor”)。 我認為對於每天從事這項工作的人來說,這都很簡單。 是的,還有另一項任務。 這些列為STRING類型,因此需要在LINQ語句中進行轉換。


是的,我剛剛將我的Parallel代碼修改為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);

            });

(前面未經測試的代碼.....)

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

靠它本身應該可以使速度更快。

現在,成功完成后,它將向上掃描范圍,直到找到匹配的范圍。 如果發生故障,它必須在放棄之前先掃描整個列表。 因此,我們要做的第一件事就是對范圍列表進行排序。 然后,我們只需掃描到范圍的低端,使其高於我們所尋找的值。 這樣可以將那些超出任何范圍的行的處理時間減少一半。

嘗試這個:-

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,因此您可以將其復制粘貼到編輯器中並進行測試。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM