[[20170515083320]] 『入力セル数のカウントについて』(外部コーチ) ページの最後に飛ぶ

[ 初めての方へ | 一覧(最新更新順) | 全文検索 | 過去ログ ]

 

『入力セル数のカウントについて』(外部コーチ)

お世話になります。

とても底レベルな質問なのですが、ネット等で調べてもプログラムまでは解るのですが、なぜこのプログラムで、どの様な経緯で値を求めているのか理解できません。

 Dim 入力セル数 As Integer

' 1行1列目から右方向の空白セルまで入力済みセル数をカウント

 Do Until Cells(1, 入力セル数 + 1).Value = ""
  入力セル数 = 入力セル数 + 1
 Loop

というプログラムです。

認識レベル
「入力セル数」について

  Dim の後の入力セル数 ⇒ 求めたい数値?
  Do Untilの後の入力セル数 + 1 ⇒ 理解できていません。 +1も
  入力セル数 = の入力セル数 ⇒ 求めたい数値?
  = 入力セル数 + 1 の入力セル数 + 1 ⇒ 理解できていません。 +1も

 入力セル数 = 入力セル数 + 1 ⇒ 入力セル数 に 入力セル数 + 1 を代入
  この辺から頭から煙が・・・。

 Do〜Loop ⇒ 条件まで繰り返し処理(条件=各当セルが空白)

 Until ⇒ 条件式がtrueの間、処理が実行

 Cells(1, 入力セル数 + 1) ⇒ ???? - 思考能力停止 -。

例えばA1からC1まで入力されていれば入力セル数は 3 になるのですが、その動きが理解できません。
以上です。

A1からE1までの文字を空白を除いてランダムに表示するプログラムの中で

col = Int(入力セル数 * Rnd + 1) ・・・例えの場合(入力セル数=3)

というプログラムがあり、その中の「3」の値を自動取得するために、はじめは別のセルにカウント関数を使って入力セル数を取得しその値を反映させていましたが、プログラムの方で処理できるのでは? と思い試みました。

とてもお恥ずかしい質問ですがご教授よろしくお願いします。

※ この質問は最終には一つのプログラムになる内の小さな質問です。何度も質問をたてていますが、この様な質問の仕方はどうなのでしょうか?
ご指摘も宜しくお願いします。

< 使用 Excel:Excel2013、使用 OS:Windows7 >


例のトレーニング用に作ってもらったコードの一部なのかと思いますが、コード内そのものずばりならば、作者の居る掲示板で尋ねるのが一番良いかと思いますね。 他者ではどういう意図かを推測するしかありませんから。
(ちなみに私は、gooに書く事はありません。あそこは広告だらけで鬱陶しいので…)

とりあえず今回の部分だけなら、誰でも理解できるので、説明しますと…。

・「入力セル数」とは、変数。Excelマクロの変数名には、日本語も使えます。(私は変数っぽくなく見えてしまうので、使いませんが)
・+1しているのは、この変数の初期値が0だから。セルの列の始まりはA列であり、1。なので、0+1 = 1列目から判定してます。
・A1〜C1が入力されていれば3になるのは、ループ条件が空欄だったら抜ける、なので、
A1:空欄ではない(変数+1、つまり1になる)
B1:空欄ではない(変数+1、つまり2)
C1:空欄ではない(変数+1、つまり3)
D1:空欄(ループを抜ける)

こうなるので、結果として 入力セル数 = 3 になるからですね。
コードの途中にブレークポイントを設定し、F8キーでステップ実行しつつ、変数の内容を確認していくことで、どういう動作なのか追ってみてください。
(???) 2017/05/15(月) 11:29


(???)さん
 回答有難う御座います。

ご察しの通りトレーニング用のプログラムに関する質問です。
ただ、今回の経緯での話ではないと思うのですが、作者様が当分掲示板を離れるとご連絡を頂いた事と、ご教授頂いたプログラムは私の能力を大きく上回る逸品だった為、コードの理解は出来ませんでした。今はそのプログラムは保存状態で私の能力が理解できるまで成長した時に解読しようと思っています。その為、1 から作り直している途中です。 すべての動作希望を書いてしまうと、ご承知の通りどの様なプログラムを使うのかはもちろんそのプログラムでどの様な計算工程でどの様な処理や条件を求めている、または求められているのか解らなくなってしまい、質問自体も何が何だか解らなくなってしまいます。おそらく私の今回の趣旨が「トレーニング用のプログラムがほしい」から「トレーニング用のプログラムを自分で作りたい」に変わった為だと思っています。その様な理由から本当に 0 の状態と知識としてご教授して頂けたらとても嬉しいです。

>「入力セル数」とは、変数。 私は・・・使いませんが

 なんとなく普通は使わないだろうな? とは思っていました。
 なれるまでという事でご勘弁して下さい。

>・+1しているのは、この変数の初期値が0だから。

 セルの始まりには 0 は無い という事ですね。

>・A1〜C1が入力されていれば3になるのは・・・

 Cells(1, 1)の理由
  Dim 入力セル数 As Integer ⇒ 入力セル数 = 0 (初期値 = 0 の為)
  Do Until Cells(1, 0 + 1).Value = ""  ⇒ 入力セル数の計 = 1 A1=入力有
  入力セル数 = 0 + 1 ⇒ 入力セル数=1で Dim の入力セル数 0 が 1 に上書
     ↓
 Cells(1, 2)の理由 
  Dim 入力セル数 As Integer ⇒ 入力セル数 = 1
  Do Until Cells(1, 1 + 1).Value = ""  ⇒ 入力セル数の計 = 2 A2=入力有
  入力セル数 = 1 + 1 ⇒ 入力セル数=2で Dim の入力セル数 1 が 2 に上書
     ↓
 Cells(1, 3)の理由
  Dim 入力セル数 As Integer ⇒ 入力セル数 = 2
  Do Until Cells(1, 2 + 1).Value = ""  ⇒ 入力セル数の計 = 3 A3=入力有
  入力セル数 = 2 + 1 ⇒ 入力セル数=3で Dim の入力セル数 2 が 3 に上書
     ↓
 Cells(1, 4)の理由
  Dim 入力セル数 As Integer ⇒ 入力セル数 = 3
  Do Until Cells(1, 3 + 1).Value = ""  ⇒ 入力セル数の計 = 4 A4=空白
     ↓
 Loopを抜ける。

と解釈しましたが宜しいでしょうか?
変数の入力セル数は 3 と 4 どちらで抜けているのでしょうか?

>ブレークポイントを設定

 この後挑戦してみます。
 設定の意味は解りましたが、設定場所と設定方法を調査中です。

段階に分けて勉強して行こうと思いますが質問の仕方に悩んでいます。
一つの掲示で色々質問した方が良いのでしょうか?
宜しくお願いします。
(外部コーチ) 2017/05/15(月) 13:58


なるほど、確かに今回コード作成してくださった方は、もう書くの止めるかも、とおっしゃっていましたね。
それならば、こちらで部分部分を聞いてみるものアリでしょう。ただ、作った人が生きているのに、第3者に尋ねるという、双方に少し失礼な行為である事は意識しておいてください。(サンプルを頂いたのだから、後は何があろうとご自身で解決しなくてはいけないのです。だから理解するのが難しいコードは…、と思っていたのですよ)

質問の際は、例えば今回の内容ならば、以下のような問題点が再現できる小コードを作ってみて、これをアップしてみてください。
これでも、聞きたい内容は同じですし、個々に聞けますよね。

 Sub test1()
    Dim 入力セル数 As Integer

    Do Until Cells(1, 入力セル数 + 1).Value = ""
        入力セル数 = 入力セル数 + 1
    Loop

    MsgBox 入力セル数
 End Sub

折角だからこのコードを元にした指導をしておきます。私だったら、このコードは、以下のようにします。

 Sub test2()
    Dim iCou As Long

    iCou = Cells(1, Columns.Count).End(xlToLeft).Column
    MsgBox iCou
 End Sub

変数名は英字にするというのは、前にも書いた通り。Excelは米国製のため、日本語を使うと、もしかすると第二水準や機種固有文字等の変わった漢字を使った場合、問題が出るかも知れない。また、質問する際に「入力セル数は入力セル数です。」とかになり、会話しにくいし、日本語で書くコメントと変数が混ざって読みにくくなったりするためです。
(日本語を使うメリットは、変数の意味が一目瞭然である事や、エルとアイ、1のように見分けにくい文字の打ち間違いがない事が考えられますので、無意味ではないと思いますが、変数名は英字にする人が多いですね)

更に、私のコードの特徴として、Doループはなるべく使いたくない(教えたくない)、という点があります。これは、Doループは条件になるまで、または条件で無くなるまで、という書き方ができるのですが、例えばセルの位置を変更する変数を変え忘れると、同じセルを見続ける事になり、いつまで経ってもループから抜けない、無限ループ状態になる可能性があるからです。もし無限ループさせてしまうと、キー入力すら出来なくなり、PCは条件チェックを全力で続けてしまう事になるのです。なので、ループはForループで教えます。今回のケースは、ループさせるまでもなく、右端からCTRL+←を入力すれば末端が得られるので、そういうコードになっています。

ちなみに、今回書いた2つのコードでは、結果が異なる場合があります。それは、調べるセルが全部空欄だったり、2番目のセルが空欄だったりする場合です。どうしてなのかは、考えてみてください。
(???) 2017/05/15(月) 14:46


(???)さん
 ご指導有難う御座います。

Sub test1()
 シートの行を左端から見に行っている。
 A列が空白だとB列以降に入力があっても値は常に0。
 B1からF1のセルからの選択には使えない。
 途中に空白があるとそれ以降のセルはカウントにいかない。
 結果空白セルはカウントしない。

Sub test2()
 シートの行を右端から見に行っている。
 最終列に入力の有る列番号が取得できる。
 A列及び途中の空白には影響されない。
 A列から空白セルもカウントする。

この様な動作の違いでしょうか?
まだ
Sub test2()
の理解が不十分でプログラムの意味がしっかり理解できていません。

 iCou = Cells(1, Columns.Count).End(xlToLeft).Column
     ↓
 iCou = Cells(1, 最大列数).最終列の取得.列番号を数値で返す。

と置き換えたのですが
A1からO1まで1列置きに空白(A1=1.B1=空白.C1=3・・・M1=空白.O1=15)としたとき

 iCou = Cells(1, Columns.Count).End(xlToLeft).Column → iCou = 15

 iCou = Cells(1, Columns.Count).End(xlToLeft) → iCou = 15

 iCou = Cells(1, Columns.Count) → iCou = 0

となりました。

どの様な経緯で、なぜこの様なコードなのかが理解できません。
ご解説宜しくお願いします。
(外部コーチ) 2017/05/15(月) 17:17


追記!

>双方に失礼な行為である事は意識しておいてください。
 深く反省しています。
 VBAが扱える様になるのがお詫びに繋がると信じて精進していきます。
 頂いたサンプルも理解出来る様に頑張ります。
(外部コーチ) 2017/05/15(月) 17:29


もう少し時間をかけて実験すれば判ったかと思いますが、少し解説。

(1)iCou = Cells(1, Columns.Count).End(xlToLeft).Column
これは教えたコードそのままですね。まず、Columns.CountやCellsは、親オブジェクトを省略していますが、Activesheetが親になります。
.End(xlToLeft)の部分は、Range.Endプロパティをヘルプで調べてみてください。 CTRL+← と同じ動作になります。これで、列の終端(空欄のはず)から、空欄で無くなる右端のセルが得られます。
入力のある右端のセルの .Columnプロパティを見る事で、列の数字が得られます。15列目だった、という事ですね。

(2)iCou = Cells(1, Columns.Count).End(xlToLeft)
これは、.Columnプロパティを省略したため、右端のセルのオブジェクトが返ります。何のプロパティの情報か指定していないので、デフォルト値、つまりセルのValueが得られます。これも15だったということは、たまたまo1セルには"15"と入力してあったのでしょう。もしo1セルが"abc"だったら、答えは"abc"になります。文字列を整数型に代入できず、エラー停止する事になりそう。プロパティを省略するとどうなるか、予想できないうちは、きっちり全てのオブジェクトはプロパティまで指定してください。

(3)iCou = Cells(1, Columns.Count)
これは、1行目で列の終端のセルの値を得る、という意味になります。列の終端なんて使っていないでしょうから、空欄ですよね。空欄 = 0 という事ですね。
(???) 2017/05/16(火) 09:39


ちなみに、CTRL+← の動作は、元のセルが空欄ならば、空欄で無くなるまで。空欄ではないならば、空欄まで飛びます。これがシートの端まで行った場合、0になるのではなく、端の値、つまり1が返ります。(手でCTRL+←と押下しても、シート外には飛びませんよね) だから、データが1件も無い場合、0にならずに1になってしまう、という制限が付くのです。

元のコードの場合、途中に空欄が登場すると、そこでカウントを止めてしまいます。なので、途中空欄を含む場合、終端の列が得られなくなります。 途中空欄の列も処理したいのか、以降は無視したいのか。 どちらで考えるかで、使うべきロジックが決まってくるでしょう。 大抵の場合、途中空欄は無いし、データ全部空欄の場合も無いので、どちらでも同じ結果が得られる、という訳です。
(???) 2017/05/16(火) 09:48


(???)さん
 ご指導有難う御座います。

なんとなく。本当になんとなくですが理解できてきた様な・・・汗。

>もしo1セルが"abc"だったら
あの後セルの列のアルファベットに合わせて数字から英字に変えて試したところ「O」と表示されました。
(1)は列番号を返し、(2)と(3)はセル内の値を返していたのですね。(プロパティーの指示がないため)

もし選択セルがC1〜H1セルでA1セルとJ1セルには他の情報があれば

iCou = Cells(1, 3).End(xlToRight).Column

というプログラムになりますか?
動作的にはうまく表示しました。

この後「△」と「▽」を指定表示時間で指定内回数交互に表示する。というプログラムに挑戦してみます。
目標のトレーニング用プログラムもこの表示から始まると思うので、かなりハードルは高いですが一度出来る所まで自力で作ってみようと思います。おそらく正常な起動はしないので、2日位お時間頂けますか?(途中で泣きがはいるかも・・・)

その時の掲示はここに続けて書いたほうが良いでしょうか?(題目からはなれますが)
ご指導の程宜しくお願いします。

PS: 今回のご教授は次の段階の指示をランダムに表示する時に使います。ループは Forループ で頑張ります。
(外部コーチ) 2017/05/16(火) 16:16


 > iCou = Cells(1, 3).End(xlToRight).Column

はい、CTRL+←を、CTRL+→ で応用したのですね。正しい使い方です。途中に抜けがないならば、これでOKです。
ちなみに、右を使う場合は左端始点は決まったセルなので、以下のように書くと、より判り易いかと思います。

 iCou = Range("C1").End(xlToRight).Column

RangeもCellsも、どちらもRangeオブジェクトであり、書き方が違うだけ、と考えてください。(突っ込んで調べると、実はこれかなり難しい話になるので、まぁ同じなんだな、くらいの理解でOKです)

今回のご質問は、連続する1行目の末尾列を得る方法としてCloseできたと思いますので、次に別な質問する際は、新しく質問を立てた方が良いでしょう。違うテーマでだらだらと長くなると、後で追いにくくなります。あと、最初から質問する気まんまんで臨まず、絶対自力で理解するのだ!、という意思で検索し、実験し、理解していってください。そして、どうしてもうまくいかなくなって、行き詰まったら、また質問してみてください。
(もらったコードの質問より、自力で書いたコードの質問のほうがベストですね。そうやって少しずつ進んだ方が、確実に上達できるでしょう)
(???) 2017/05/16(火) 16:49


(???)さん
ご指導有難う御座いました。

時間はかかってしまうと思いますが、頑張ってみようと思います。
一旦この掲示は締めさせて頂きます。
プログラムが出来ましたら新規掲示しようと思いますので、その際は宜しくお願いします。
色々とご指導いただき本当に有難うございました。
(外部コーチ) 2017/05/16(火) 18:29


コメント返信:

[ 一覧(最新更新順) ]


YukiWiki 1.6.7 Copyright (C) 2000,2001 by Hiroshi Yuki. Modified by kazu.