トップ回答者
VB LINQでのSelect, Group Byのコード作成

質問
-
データが格納済みのデータセット・テーブルからLinqで新たなデータセット・テーブルを作成しようと試みておりますが、どうも上手くいかず困っています。以下にどんな事をやりたいか例示しますので、コードでご教示下さいますようお願いいたします。
データ格納済みのデータセット・テーブル(DataSet1.DataTable1)の内容
YYYYMMDD/HHMMDD/HighPrice/LowPrice/Volume
------------------------------------------
20100103/000000/100.10/100.05/10△
20100103/000100/100.15/100.10/10
20100103/000200/100.20/100.15/10
20100103/000300/100.30/100.25/10○
20100103/000400/100.20/100.10/10
20100103/000500/100.20/100.45/10
20100103/000600/100.35/100.25/10
20100103/000700/100.25/100.15/10
20100103/000800/100.45/100.30/10○
20100103/000900/100.00/99.90/15△
20100104/000000/100.50/100.45/15○
20100104/000100/100.50/100.40/15
20100104/000200/100.45/100.45/15
20100104/000300/100.37/100.35/15
20100104/000400/100.30/100.20/15△
20100104/000500/100.25/100.20/30
20100104/000600/100.35/100.25/15
20100104/000700/100.50/100.05/20○△
20100104/000800/100.45/100.40/20
20100104/000900/100.10/100.10/20
以上のデータを新たなデータセット・テーブル(DataSet1.DataTable2)を作成する必要があります。
抽出条件
①YYMMDD毎 (以上の例では20100103と20100104となります。)
②HHMMDDが500毎(以上の例では次の2つの組合せとなります。000000~000400、000500~000900)
③HighPriceは①と②の最大値 (以上の例ではレコードの横に○を付けています)
④LowPriceは①と②の最小値 (以上の例ではレコードの横に△を付けています)
結果出力。注意点としてはHHMMDDは500毎となります。つまり、00000~000400は000500となり、000500~000900は001000となります。なおVolumeは不要となります。
YYYYMMDD/HHMMDD/HighPrice/LowPrice
------------------------------------------
20100103/000500/100.30/100.05
20100103/001000/100.45/99.90
20100104/000500/100.50/100.20
20100104/001000/100.50/100.05
非常にややっこしいですが、初心者のため実際のコードで教えてくださいますようお願いいたします。
回答
-
なるほど、LINQ 自体はあまり問題になってなくて、話の中心は「どうやって 500 ずつに区切るか」ということですね。
なら単純な話で、(HHMMDD を Integer に変換した後)500 で整数除算してやればオッケーです。0~499 なら 0 になりますし、500~999 なら 1 になります。
この値を Group の By 句に追加すればグループ化できますし、この値から 500 刻みの値にするのも計算で簡単に求まりますよね。
すべての返信
-
返信ありがとうございます。完全に丸投げのつもりではなく、以下まで作成しております。
しかし、500毎の取得が出来ずに困っています。
自分のコードの正しさも不明ですし、各人作成方法が異なると思ったので以前の形式で投稿してみました。
Dim query As IEnumerable = From order As DataRow In DataTable1.AsEnumerable _
Select DataTable1YYYYMMDD = order.Field(Of String)("YYYYMMDD"), _
DataTable1HHMMDD = order.Field(Of Single)("HHMMDD"), _
DataTable1HighPrice = order.Field(Of Single)("HighPrice"), _
DataTable1LowPrice = order.Field(Of Single)("LowPrice")
Group order By DataTable1HHMMDD = 500 Order By DataTable1YYYYMMDD
Into DataTable1HighPrice = Max(order.Field(Of Single)("HighPrice")), _
DataTable1LowPrice = Min(order.Field(Of Single)("LowPrice")) _
Select New Object() {DataTable1YYYYMMDD, DataTable1HHMMDD DataTable1HighPrice, DataTable1TBLLowPrice}
For Each order As Object() In query
DataTable2.Rows.Add(order)
Next order
ありがとうございました。
- 編集済み tsutomu0111 2011年10月6日 4:57
-
なるほど、LINQ 自体はあまり問題になってなくて、話の中心は「どうやって 500 ずつに区切るか」ということですね。
なら単純な話で、(HHMMDD を Integer に変換した後)500 で整数除算してやればオッケーです。0~499 なら 0 になりますし、500~999 なら 1 になります。
この値を Group の By 句に追加すればグループ化できますし、この値から 500 刻みの値にするのも計算で簡単に求まりますよね。
-
// なんか LINQ の記述レベルとアンバランス……。
LINQ 中に各行の HHMMDD がそれぞれどうなのかというのを調べたいのに、LINQ の外でやる意味はないでしょう。
たとえば、初めの方で Select 句を使って各メンバを型付きにしてますが、このタイミングで HHMMDD を変換しちゃうとか。どうせ元の HHMMDD の値を使うことはないのだし。
あと、VB では普通の除算演算子( / ) だと浮動小数点数(Double)を返します。整数部だけを返す整数除算演算子は別に用意されているので調べてみてください。
- 回答の候補に設定 山本春海 2011年10月26日 8:23
-
// なんか LINQ の記述レベルとアンバランス……。
経験がないので、本3冊とネットで仕入れた情報を組み合わせて、何度も間違いながらやっと何とか出来たコードですので、そう思われるのでしょう。
//Select 句を使って各メンバを型付きにしてますが、このタイミングで HHMMDD を変換しちゃうとか。変換は何度も試しているのですが、まずLinq to SQLでAccessから取ってきたデータをデータセット・テーブルに入れてから、それから上述のコードを作成しています。Integer型は遡及して試してはみましたが、駄目でした。
//VB では普通の除算演算子( / ) だと浮動小数点数(Double)を返します。整数部だけを返す整数除算演算子は別に用意されているので調べてみてください。
ありがとうございました。