Excel VBA質問箱 IV

当質問箱は、有志のボランティア精神のおかげで成り立っています。
問題が解決したら、必ずお礼をしましょうね。
本サイトの基本方針をまとめました。こちら をご一読ください。

投稿種別の選択が必要です。ご注意ください。
迷惑投稿防止のため、URLの入力を制限しています。ご了承ください。


3705 / 13646 ツリー ←次へ | 前へ→

【60578】解説して頂きたい。 こまつ 09/3/3(火) 16:25 質問[未読]
【60580】Re:解説して頂きたい。 超初心者 09/3/3(火) 16:55 発言[未読]
【60581】Re:解説して頂きたい。 こまつ 09/3/3(火) 17:09 発言[未読]
【60584】Re:解説して頂きたい。 kanabun 09/3/3(火) 20:22 発言[未読]
【60587】Re:解説して頂きたい。 こまつ 09/3/3(火) 23:20 お礼[未読]
【60594】Re:解説して頂きたい。 kanabun 09/3/4(水) 10:30 発言[未読]
【60595】Re:解説して頂きたい。 kanabun 09/3/4(水) 10:52 発言[未読]

【60578】解説して頂きたい。
質問  こまつ  - 09/3/3(火) 16:25 -

引用なし
パスワード
   Sub 支社別集計()
  Dim Sheet1, Sheet2 As Worksheet
  Const COL店舗CD = 1 ' 店舗CDの列
  →Const name = 1でなぜ、1列目みてるのでしょうか?

  Const COL分類CD = 3 ' 分類CDの列
  Const COL売上額 = 10 ' 売上額
  Dim MaxRow As Long ' 最終行
  Dim key As String ' 検索キー
  Dim c, r As Long
  
  Set dicT = CreateObject("Scripting.Dictionary") ' 連想配列の定義
  
  Set Sheet1 = Worksheets("売上明細") ' 明細シート
  Set Sheet2 = Worksheets("売上集計") ' 集計シート
  
  MaxRow = Sheet1.Cells(Rows.Count, 1).End(xlUp).Row ' 最終行を求める
  →なぜ上の文で最終行を取得できるのでしょうか?
   Rows.Count,1とは、どこをみてるのでしょうか?

  ' 売上明細を連想配列へ読み込む
  With Sheet1
    For r = 2 To MaxRow ' 最終行
      key = .Cells(r, COL店舗CD) & .Cells(r, COL分類CD) ' 店舗CD & 分類CD
      →Cells(r,COL店舗CD)とは、なんですか?
       Cells(2,1列??)

      dicT(key) = dicT(key) + .Cells(r, COL売上額) ' 売上額
      →一回目のdicTには、108400という数字が入ってます。
      →なぜ上の数式で売上額になるのでしょうか?
    Next
  End With
    
  ' 集計シートへの書き出し
  With Sheet2
    For c = 3 To 12 ' 列
      For r = 4 To 12 ' 行
        key = .Cells(2, c) & .Cells(r, 1) ' 店舗CD & 分類CD
        .Cells(r, c) = dicT(key)
      Next
    Next
  End With
End Sub

宜しくお願いします。
一行一行説明して頂けるとさらに助かります。

【60580】Re:解説して頂きたい。
発言  超初心者  - 09/3/3(火) 16:55 -

引用なし
パスワード
   ▼こまつ さん:
作った人に聞くのが一番です。

聞けない状況であれば、分からないところのキーワードを
全てヘルプにて確認してください。

例題コードなどが載ってるものもありますので、
そういったものと比べながら見てみるともう少し理解できます。

書籍なども数冊、目を通した方が良いかもしれません。

【60581】Re:解説して頂きたい。
発言  こまつ  - 09/3/3(火) 17:09 -

引用なし
パスワード
   ▼超初心者 さん:
>▼こまつ さん:
>作った人に聞くのが一番です。
>
>聞けない状況であれば、分からないところのキーワードを
>全てヘルプにて確認してください。
>
>例題コードなどが載ってるものもありますので、
>そういったものと比べながら見てみるともう少し理解できます。
>
>書籍なども数冊、目を通した方が良いかもしれません。

作った方には聞けないのです。
ヘルプを見て多少は理解したつもりですが、
なんていうか、完全理解とまではいかないのです。

宜しくお願いします。

【60584】Re:解説して頂きたい。
発言  kanabun  - 09/3/3(火) 20:22 -

引用なし
パスワード
   ▼こまつ さん:

>   Const COL店舗CD = 1 ' 店舗CDの列
>   Const COL分類CD = 3 ' 分類CDの列
>   Const COL売上額 = 10 ' 売上額

Const とは 「定数」(プログラムのなかで変化することのない固定値)
   を宣言しているわけですね。
 Constステートメントについては
  ヘルプの目次 より
   ≪VisualBasic プログラミングのヒント≫ のなかの
    ≪定数の宣言≫ というトピックを参照してください。

>→Const name = 1でなぜ、1列目みてるのでしょうか?
というか、
>   Const COL店舗CD = 1 ' 店舗CDの列
で唱っていることは、このプロシージャのなかで「COL店舗CD」という
文字列に出喰わしたら、そこを数値1 に置き換えて処理するように、と
定義しているわけです。で、「COL店舗CD」という定数Constantがどこで
使われているか見てみると、
> .Cells(r, COL店舗CD)
のように使われている。
では、そもそも
> →Cells(r,COL店舗CD)とは、なんですか?
となる。
そこでまたもや ヘルプの Cellsプロパティの項を開いてみると、
 ▼Worksheet.Cells プロパティ
  ワークシートのすべてのセル (現在使用されていないセルも含む) を
  表す Range オブジェクトを返します。
とあり、ワークシート上のすべてのセルの集合(コレクション)を取得
できるものであるらしいことが(一応)解る。
では
> Cells(r,COL店舗CD)
のように、Cellsのうしろのカッコのなかにある2つのパラメータは何か?
Cellsコレクションの解説を読んでいくと、Itemプロパティによってコレ
クション内の個別要素を指定できるらしいことが書いてある。
 ↓
>Cellsキーワードの後に続けて行および列のインデックスを指定できます。
 ↓
ということは、Cells(r,COL店舗CD) は Cells.Item(r,COL店舗CD) が省略
されたものであり、ワークシートのすべてのセルの集合のなかの一つの要
素Item (具体的にその位置は  行番号が r で、列番号が COL店舗CD と
いう位置)を指定していることが分かる。。
というわけで、
> Cells(r,COL店舗CD)
は、 COL店舗CD = 1 (列番号) とプログラムの先頭で宣言してあるから、
 Cells(r,1)  …… 全セルのなかでの要素(r行目、1列目) の単一セル
のことだと分かる?


>MaxRow = Sheet1.Cells(Rows.Count, 1).End(xlUp).Row ' 最終行を求める
> →なぜ上の文で最終行を取得できるのでしょうか?
>  Rows.Count,1とは、どこをみてるのでしょうか?

Sheet1.Cells(Rows.Count, 1) とは
Sheet1.Cells.Item(Rows.Count, 1) ということで、これは
  行番号が ワークシートの全行数(Rows.Count)
  列番号が 1
のセル( Cells(65536, 1) ですから セル[A65536] )のことです。
そのあとの .End(xlUp) は キーボードから [Ctrl] + [↑]を押下した動作に
なります。Cells(65536, 1) から [Ctrl] + [↑] としてA列でデータのある
最後のセルにジャンプする操作をマクロ記録してみてください。
すぐ分かります。
同じように、1行目でシートの一番右端 [IV1] に行ってそこから 1行目で
データのあるいちばん左端のセルへジャンプするには [Ctrl] + [←]ですが、
これをコードにするとどうなりますか?
答えは マクロ記録してみるとすぐ分かります。


  dicT(key) = dicT(key) + .Cells(r, COL売上額) ' 売上額
>   →一回目のdicTには、108400という数字が入ってます。
>   →なぜ上の数式で売上額になるのでしょうか?

連想配列 dictionary というものobjectを一から説明するのは至難の業で
す。まず、単独変数ではなく「配列」変数がどういうときに利用されるか
を理解する必要があるでしょう。
あまりいい例ではないのですが、
 dim 支店名(1 to 3) as string
 dim 売上高(1 to 3) as double
とすると、普通の配列を2個用意したことになります。
そこに、ある月の売上高を代入していくときは = を使います。
  支店名(1) = "東京本社"
  支店名(2) = "大阪支店"
  支店名(3) = "札幌支店"
  売上高(1) = 332400
  売上高(2) = 65900
  売上高(3) = 33240
札幌支店の売り上げは? 「札幌支店」の配列内のIndexが 3であるこ
とが分かっていれば、 MsgBox 売上高(3)
で答えが求まります。では 「札幌支店」の配列内のIndexが 分からない
ときは どうしますか?
for idx = 1 to UBound(支店名)
  if 支店名(idx) = "札幌支店" then
    MsgBox "札幌支店のIndexは " & idx & " です"
    exit for
  end if
next
みたいに 支店名配列内から indexを求めておいて 得られたindexを
使って
  MsgBox "札幌支店の当月の売上高は " & 売上高(idx)
とします。
では、支店名も分からないとき、さらに、売上高が集計されていない
以下のような表データのときはどうしますか?
  A       B       C
 東京本社    3000     2009/1/15
 大阪支店    3200     2009/1/15
 東京本社    9000     2009/1/20
 大阪支店    3000     2009/1/20
 札幌支店    4500     2009/1/10
 名古屋支店  12300     2009/1/25

このようなときは 連想配列を使います。
dictioanryでは 最初に宣言するのはobjectの使用宣言だけです。
> Set dicT = CreateObject("Scripting.Dictionary")

サイズ(dimension)は宣言しません。そして
レコードの代入は次のように、キーとアイテムのペア(組み)で
レコードをセットします。(↓最初のデータ)
  dicT("東京本社") = 3000
これは "東京本社" というラベルをもつ容器に 3000というアイテム
を放り込むことを意味します。一番初めは「東京本社」というラベル
名の容器は存在しませんから、この一行で「東京本社」というラベル
をもった容器が用意され、そのなかに 3000 という数値が入れられる
ことになります。
2度目の「東京本社」のときは すでに 「東京本社」というラベルの
容器は存在しますから、9000を加算すればいいのですが、
  dicT("東京本社") = 9000
ではまずいことは分かりますね? この構文では、すでに「東京本社」
容器内にある 3000 という数字が 9000 に置き換えられて、常に最後の
売上高しか残りません。そこで、あなたのコードにあるように、
  dicT("東京本社") = dicT("東京本社") + 9000
に修正します。
こう書いておくと、
1回目の「東京本社」データのときには、
  dicT("東京本社") = 0 + 3000
2回目の「東京本社」データのときには、
  dicT("東京本社") = 3000 + 9000
 :
 :
のように、支店名別に用意された入れ物に アイテム(売上高)が加算さ
れて集計ができることになります。

連想配列については
Wikipedia より
連想配列(れんそうはいれつ)とは、プログラミング言語において、
添え字にスカラー数値以外のデータ型(文字列型等)も使用できる
配列である。… 連想リスト、連想コンテナ、辞書とも呼ばれる。

連想配列を使う
ht tp://officetanaka.net/excel/vba/tips/tips52.htm

Dictionaryオブジェクトを使って重複しないリストを作成する
ht tp://officetanaka.net/excel/vba/tips/tips80.htm

などが、とっかかりとなるでしょう。

>  dicT("東京本社") = dicT("東京本社") + 9000
という記述法以外の書き方もそこに書いてあります。

ま、こういうことはたくさん例題をこなして行くうち、螺旋的に分かって
くることが多いので、分かるところから 実践でどんどん使って慣れてください。

ではでは。

【60587】Re:解説して頂きたい。
お礼  こまつ  - 09/3/3(火) 23:20 -

引用なし
パスワード
   ▼kanabun様
感謝致します!!
大変わかりやすく、理解できました。たぶんw

Cells(rows.count,1)=cells(A65536,1)なら、別に後者を記述しても
間違いではないんですよね?

たとえば、Excelの最後の行数が10000までなら、rows.count,1は、
(A10000,1)ってことなんですね。あってるかな?

Constはなぜ宣言したのでしょうか?
毎回、列番号打ってもいいのではないのでしょうか?
逆にCOL店舗CDって記述する方が、めんどーな気がするのですが。
後から見てわかり易いって事なんですか?
それとも連想配列で読み込ませるときには、Constしとかないと、
だめだったのでしょうか?
ん〜普通の配列をもっと勉強します。
最低限、ヘルプの内容を理解できるようにします。

ほんとすいません。だめもとでお願いしたのですが、
ここまで、解説して頂いて申し訳ないです。
無駄にしないように、がんばります。
ありがとうございました。

【60594】Re:解説して頂きたい。
発言  kanabun  - 09/3/4(水) 10:30 -

引用なし
パスワード
   ▼こまつ さん:
>▼kanabun様
>感謝致します!!
>大変わかりやすく、理解できました。たぶんw
>
>Cells(rows.count,1)=cells(A65536,1)なら、別に後者を記述しても
>間違いではないんですよね?
>
Excel2003までのワークシートなら
Cells(Rows.count,1) = Cells(65536,1) で, 同じことです。
              ~~~~~A65536ではありません
また、Cells(65536, 1) と Range("A65536") は同じセルです。
(余談)
 Cells(65536, 1) は Cells(65536, "A") と書くこともできます。
 列番号の代わりに列名を使っているわけですが、シート内に
 グラフがあるときはこの記述法は使わないほうがいいです。
 グラフが選択されてると、Cells(65536, "A")ではExcelが迷走して
 しまいます。
>たとえば、Excelの最後の行数が10000までなら、rows.count,1は、
>(A10000,1)ってことなんですね。あってるかな?
あってないですね。ご自分で訂正してください。

>Constはなぜ宣言したのでしょうか?
>毎回、列番号打ってもいいのではないのでしょうか?
>逆にCOL店舗CDって記述する方が、めんどーな気がするのですが。
>後から見てわかり易いって事なんですか?
>それとも連想配列で読み込ませるときには、Constしとかないと、
>だめだったのでしょうか?

名前でなんらかの固定数値を別名定義する理由は、こまつさんの
推定のうち前者に該当します。後者(連想配列云々)とは無関係
です。
>毎回、列番号打ってもいいのではないのでしょうか?
>逆にCOL店舗CDって記述する方が、めんどーな気がするのですが。
という疑問は現段階では しごく「ごもっとも」な感想ですが、
実際はプログラムのはじめに
「このプロシージャのなかで <COL店舗CD> とは 数値1を意味する」
とConst宣言しておくと、
  Cells(Rows.Count, 1)
よりも
  Cells(Rows.Count, COL店舗CD) '←店舗CDのある列番号
と書いてあるほうが、どういう列を参照しているのか意味が分かり
やすいじゃないですか? 「COL」は Column(列)の意味でしょうし、
「後から見てわかり易い」どころか、プログラムを書いている現時
点ですでに 定数名を使うことのメリットが出ていますよ。
>COL店舗CDって記述する方が、めんどーな気がする
そんなにめんどーではないですよ、
  cells(rows.count, col
 までタイプして Ctrl+[スペース]キー で候補が出ますでしょ?
 そこから選べばいいのです(TABキーで確定)

Cells はセルの集合すなわち セルのコレクションだということを
覚えておきましょう。
すると、Worksheets(1).Cells(1) というコードが
Worksheets.Item(1).Cells.Item(1) の簡便表現であり、
ワークシートの集合の1番目のアイテムの全セルの集合内の
1番目の要素のことを表していることが理解しやすくなります。

セル範囲の指定の仕方は状況に応じて RangeプロパティとCellsプロパティ
を使い分けます。
  Worksheets(1).Cells.ClearContents
は ワークシート1のすべてのセルの値を初期化します。
まだ使われてないセルをクリアする必要はないので
  Worksheets(1).UsedRange.ClearContents
のほうが分かりやすいかと思います。
Range("C1").Cells(2,1) というのは Range("C1").Cells.Item(2,1) のこと
で、[C2]という単一セルを参照しています。
Range("C1").Range("A1:E1") といえば、[C1]セルを基点[A1]として
右方向に5つのセル要素を表しますから、[C1:G1]になります。。。
などなど、
 ご自分で問題を作って 試されるとよいでしょう。

【60595】Re:解説して頂きたい。
発言  kanabun  - 09/3/4(水) 10:52 -

引用なし
パスワード
   あと、定数の逆、「変数」名の定義ですが、

> Sub 支社別集計()
>  Dim Sheet1, Sheet2 As Worksheet

Dim Sheet1 のあとにも As Worksheet を付けないといけない。
さらに、 Sheet1 とかは オブジェクト名としてExcelが使ってますので、
競合しない方がいいと思います。
二つのワークシートを変数で使うのなら、たとえば、

Dim WS1 As Worksheet, WS2 As Worksheet

とか?

3705 / 13646 ツリー ←次へ | 前へ→
ページ:  ┃  記事番号:
2610219
(SS)C-BOARD v3.8 is Free