2016-07-11 22 views
2

完全公開,我幾乎是一個總noob,當談到linq。我可以基於我應該如何接近這一點。在linq中使用數據總和和分組

我有一個DataTable 3列

OID,IDATE,量

每個ID有多個日期,每個日期有多個數額。我需要做的是和每天每個ID的數量,所以不是:

  • 編號,日期,金額
    • 00045,02/13/2011,11.50
    • 00045, 2月14日/ 2011,11.00
    • 00045,02/14/2011,12.00
    • 00045,02/15/2011,10.00
    • 00045,02/15/2011,5.00
    • 00045,02/15/2011,12.00
    • 00054,02/13/2011,8.00
    • 00054,02/13/2011,9.00

我會:

  • 編號,日期,SumOfAmounts
    • 00045,02/13/2011,11.50
    • 00045,02/14/2011,23.00
    • 00045,02/15/2011,27.00
    • 00054,02/13/2011,17.00

private void excelDaily_Copy_Into(DataTable copyFrom, DataTable copyTo) 
{ 
    var results = from row in copyFrom.AsEnumerable() 
    group row by new 
    { 
     oid = row["oid"], 
     idate = row["idate"] 
    } into n 
    select new 
    { 
    ///unsure what to do 
    } 
}; 

我試着做的十幾個不同的方式這和我總是有點撞牆,我無法弄清楚如何進步。我一直在堆棧溢出和MSDN,迄今沒有任何事情真的幫助過我。

預先感謝您!

回答

2

你可以試試這個:

var results = from row in copyFrom.AsEnumerable() 
       group row by new 
       { 
       oid = row.Field<int>("oid"),// Or string, depending what is the real type of your column 
       idate = row.Field<DateTime>("idate") 
       } into g 
       select new 
       { 
       g.Key.oid, 
       g.Key.idate, 
       SumOfAmounts=g.Sum(e=>e.Field<decimal>("amount")); 
       }; 

我建議使用Field擴展方法提供指定行中的強類型訪問每個列的值。

+0

謝謝,這是我需要什麼。所以,如果我想通過oid訂購它,那麼我會在選擇新品之前做一個訂單。 編輯:對不起,沒有意識到它是迷你Markdown。 –

+0

一個簡單的方法可以做到這一點:'result = result.OrderBy(e => new {e.oid,e.idate});' – octavioccl

1

雖然您沒有指定它,但顯然copyFrom是實現IEnumerable的DataTable類的對象。根據MSDN System.Data.DataTable該類不會實現它。如果您使用的類,你需要財產行,返回實現IEnumerable行的集合:

IEnumerable<DataRow> rows = copyFrom.Rows.Cast<DataRow>() 

但如果你使用一個不同的DataTable類,你可能會做一些類似它轉換爲一個序列的東西的DataRow。

System.Data.DataRow類的對象具有用於訪問行中列的項屬性。在你的情況下,列名是oid,idate和amount。

爲了您的copyfrom轉換成你想要做的處理項目的順序是:

var itemsToProcess = copyFrom.Rows.Cast<DataRow>() 
    .Select(row => new 
    { 
     Oid = row["oid"], 
     Date = (DateTime)row["idate"], 
     Amount = (decimal)row["amount"], 
    }); 

我不知道,但我認爲列IDATE包含日期和金額欄包含一些價值。如果您的列包含其他類型,請隨意使用其他類型。

如果列包含字符串,並將其轉換爲使用解析正確的項目:

var itemsToProcess = copyFrom.Rows.Cast<DataRow>() 
    .Select(row => new 
    { 
     Id = (string)row["oid"], 
     Date = DateTime.Parse((string) row["idate"]), 
     Amount = Decimal.Parse (string) row["amount"]), 
    }); 

如果你不熟悉的lambda表達式。它幫了我很多,如下所示來閱讀:

itemsToProcess是項目的集合,從 數據行,其中從這個集合中的每一行,我們創建了一個新 對象具有三個屬性的集合採取:身份證= ...;數據= ...;金額= ...

現在我們有一個順序,我們可以比較日期和總結的數額。

你想要什麼,是將這個序列中的所有項目分組到具有相同ID和日期的組中。因此,您需要一個ID = 00045和日期= 02/13/2011的組,以及ID = 00045和日期= 2011年2月14日的組。

爲此您使用Enumerable.GroupBy。作爲選擇器(=共用一組中的所有項目)您使用Id和日期的組合:

var groups = itemsToProcess.GroupBy(item => new 
    {Id = item.Id, Data = item.Data}); 

現在您有組。

  • 每個組都有一個屬性Key,它具有兩個屬性:Id和Data。
  • 每組從itemsToProcess藏品序列(所以它是一個「itemToprocess」與ID /數據/ Value屬性)
  • 在一個組中的所有項目都使用相同ID和相同的數據。

所以你所要做的就是將每個組中的序列中的所有元素求和。

var resultSequence = groups.Select(groupItem => new 
{ 
    Id = groupItem.Key.Id 
    Date = groupItem.Key.Date, 
    Sum = groupItem.Sum(itemToProcess => itemToProcess.Value, 
} 

所以把他們放在一起爲一個語句:

var resultSequence = copyFrom.Rows.Cast<DataRow>() 
    .Select(row => new 
    { 
     Id = (string)row["oid"], 
     Date = DateTime.Parse((string) row["idate"]), 
     Amount = Decimal.Parse (string) row["amount"]), 
    }) 
    .GroupBy (itemToProcess => new 
    { 
     Id = item.Id, 
     Data = item.Data 
    }); 
    .Select(groupItem => new 
    { 
     Id = groupItem.Key.Id 
     Date = groupItem.Key.Date, 
     Sum = groupItem.Sum(itemToProcess => itemToProcess.Value, 
    }); 
+0

不是'AsEnumerable()'函數的目的是使DataTable '可訪問? [鏈接](https://msdn.microsoft.com/en-us/library/system.data.datatableextensions.asenumerable(v = vs.110).aspx) 有沒有一些好處,以鑄造一個'DataTable '按照你指定的方式? 另外,感謝您的額外信息!我很難找到有用的linq教程,這些教程既不是特定的案例,也不是非常淺的解釋。 –

+0

如果您不指定名稱空間,則會發生這種情況。顯然你談論System.Data.DataTableExtensions.AsEnumerable()時,我正在談論System.Linq.AsEnumerable,顯然你的AsEnumerable返回一個EnumerableRowCollection實現IEnumerable < TRow >。如果您看到一些實現IEnumerable的集合類(通常相當古老),並且確信集合中的所有項都是MyType類型,則可以使用Cast < MyType >()(如我的示例中所示)將其設置爲IEnumerable < MyType >(請參見System。 Linq.Enumerable.Cast) –