2016-07-11 7 views
2

完全な開示、私はlinqに来るかなり多くのnoobです。どのように私はこれに近づくべきであるかのベースの方法になる可能性があります。Datarowsを使用してlinqで合計とグループ

私はDataTable 3の列

OID、IDATE、量

を持っている各IDは、複数の日付を持っており、それぞれの日付は、複数の金額を持っています。私は何をする必要があることは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

私が持っているでしょう:

  • ID、日付、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でそれを注文したいと思ったら、私はselect newの直前でorderbyをやるでしょう。 編集:申し訳ありませんが、それがミニMarkdownだったことを認識していませんでした。 –

+0

これは簡単な方法です: 'result = result.OrderBy(e => new {e.oid、e.idate});' – octavioccl

1

明示的に指定しませんが、copyFromは、IEnumerableを実装するクラスDataTableのオブジェクトです。

MSDN System.Data.DataTableによれば、クラスはそれを実装していません。

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

いますが、違うのDataTableクラスを使用する場合、あなたはおそらくシーケンスにキャストに似た何かをやる:あなたは、そのクラスを使用する場合は、IEnumerableを実装した行のコレクションを返し、プロパティの行を必要とします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"]), 
    }); 

。次のようにそれを読むために私をたくさん助けた:

itemsToProcessは、各行から、このコレクションでは、我々は3つのプロパティを持つ新しい オブジェクト作成 でDataRowのコレクションから取られたアイテムのコレクション、です:同上= ...;データ= ...;金額は= ...

キャスト用

を選択するには、今、我々は日付を比較して金額を合計することができます配列を有します。

このシーケンスのすべてのアイテムを、同じIDと日付のグループにグループ化します。ですから、Id = 00045とDate = 02/13/2011のグループとId = 00045とdate =、02/14/2011のグループが必要です。

この場合、Enumerable.GroupByを使用してください。セレクタ(=グループ内のすべてのアイテムを共通に持つもの)では、IDと日付の組み合わせを使用します。

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

これでグループが作成されました。

  • 各グループには、IDとデータの2つのプロパティを持つタイプのプロパティKeyがあります。
  • 各グループ一つのグループ内のすべての項目は、同じIDと同じデータを持っている
  • (それは、ID /データ/値のプロパティを持つ「itemToprocess」である)あなたのitemsToProcessコレクションから項目の順序されます。

あなたがしなければならないことは、各グループのシーケンスのすべての要素を合計することだけです。

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

だから、1つの文にすべて一緒にそれを置く:

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 'アクセス可能? [link](https://msdn.microsoft.com/en-us/library/system.data.datatableextensions.asenumerable(v = vs.110).aspx) 「DataTableあなたが指定した方法で? また、追加情報をありがとうございます!私は、大事な事例や非常に浅い説明ではない有用なlinqチュートリアルを見つけるのが難しかった。 –

+0

これは、名前空間を指定しない場合に発生します。 System.Linq.AsEnumerableについて、System.Data.DataTableExtensions.AsEnumerable()について話しているようですが、AsEnumerableはIEnumerable < TRow >を実装するEnumerableRowCollectionを返します。 IEnumerableを実装するコレクションクラス(通常はかなり古いコレクション)があり、コレクションのすべてのアイテムがMyType型であることが確実である場合は、この例のようにキャスト< MyType >()を使用してIEnumerable < MyType >にすることができます。 Linq.Enumerable.Cast) –

関連する問題