Excel (VBA)

Excel VBAに関するフォーラムです。
  • 解決済みのトピックにはコメントできません。
このトピックは解決済みです。
質問

 
(指定なし : 指定なし)
「配列で比較して不一致の時別のシートにコピーする」の「koikoi5151」さんへ
投稿日時: 17/12/20 18:04:43
投稿者: もこな2

http://www.moug.net/faq/viewtopic.php?t=76587
投稿内容を推敲していたら↑が閉じてしまったので、こちらで追加回答します。
 
ちょっと時間があったので、連想配列をつかって「出力」へ出力する処理を考えてみました。
もうおなかいっぱいかもしれませんが、興味があったら研究してみてください。
(ツッコミどころ満載かもしれませんが。。。)
なお、出力される順番は、「Sheet2」の順の下に「Shee1」のみにあるID順となります。(たぶん)
<条件>
おなじIDが「Sheet2」と「Sheet1」にある場合、更新データと見なして、「Sheet1」の方を出力
IDが「Sheet2」にしかない場合、変更無しとみなして、「Sheet2」をそのまま出力
IDが「Sheet1」にしかない場合、新規とみなして、「Sheet1」をそのまま出力
ほしいデータは、A列、C列、E列、G列
出力はA〜D列に出力
なお、個々の値に,(カンマ)は含まれないものとする
その他、「Sheet2」、「Sheet1」それぞれのシートのA列に歯抜け(ブランク)は無いものとする。
 
余談ですが、以下条件も考えたのですが、よく考えたらそれは「Sheet1」のデータそのままですからこちらは考慮してません。
 <条件>
 おなじIDが「Sheet2」と「Sheet1」にある場合、更新データと見なして、「Sheet1」の方を出力
 IDが「Sheet2」にしかない場合、データベースから削除とみなして、出力無し
 IDが「Sheet1」にしかない場合、新規とみなして、「Sheet1」をそのまま出力
 
 

Sub Sample3()
'===変数の宣言とか
Dim objDIC As Object
Set objDIC = CreateObject("Scripting.Dictionary")
Dim Mykey As Variant
Dim i As Long


'===いったん、Sheet2のデータをA列(ID)をキーにして「objDIC」に格納
With ThisWorkbook.Worksheets("Sheet2")
    For i = 2 To .Cells(.Rows.Count, 1).End(xlUp).Row
        objDIC(.Cells(i, 1).Value) = _
            .Cells(i, "C").Value & "," & .Cells(i, "E").Value & "," & .Cells(i, "G").Value
    Next i
End With

'===つぎに、Sheet1のデータでA列(ID)が「objDIC」に登録されていれば更新、
'===登録されていなければ「objDIC」に追加
With ThisWorkbook.Worksheets("Sheet1")
    For i = 2 To .Cells(.Rows.Count, 1).End(xlUp).Row
        objDIC(.Cells(i, 1).Value) = _
            .Cells(i, "C").Value & "," & .Cells(i, "E").Value & "," & .Cells(i, "G").Value
    Next i
End With

'===「objDIC」からkeyを、配列変数(一次)に取り出す
Mykey = objDIC.keys

'===「出力」へ出力
With ThisWorkbook.Worksheets("出力")
    For i = 1 To objDIC.Count
        .Cells(i + 1, "A").Value = Mykey(i - 1)
        .Range(.Cells(i + 1, "B"), .Cells(i + 1, "D")).Value = _
            Split(objDIC(Mykey(i - 1)), ",")
    Next i
End With

End Sub

(補足)
出力シートのクリアとか、オブジェクト変数の解放とかは割愛します。
 
「出力」へ出力のところで、やたら+−してるのは、
Mykeyは0からスタート
objDIC.Countは1からスタート
書込行は2行目からスタート
という事情があるからです。(やってみると解るかと思いますが)
 
このほか、基本的に回答者は学ぶ(=自分で理解して作ろうという)気持ちがある質問者は大歓迎なので、ばしばし質問していいとおもいますよ。
私なんかは、回答したうえで、他の回答者にツッコミいれてもらって便乗学習してますし。。
 
ダメなのは、マクロを作って下さいという作成依頼です。(掲示板の規約で駄目です)
しばらく開けておくので質問あれば書き込んでください。
私がわからなくても、ほかの回答者さんが颯爽と答えてくれるかもしれません
 

回答
投稿日時: 17/12/20 19:56:05
投稿者: baoo

便乗でコメントさせてください。
私の配列マクロですが、後半でカッコ悪い部分があります。
それはタイトルとしてvarTitleを貼り付ける処理で貼り付け先の指定に
Uboundを使っているところです。
ここはlngDColsを指定すべきです。
どっちも同じ値の筈なので動作は変わらないのですが。
 
元々最初はlngDRowsもlngDColsもsheet1、sheet2で使いまわすつもりで組んでいました。
sheet1とsheet2では行数が違うはずですし、列数が違っている可能性も考えて
両者のデータを配列に入れてからはlngDCols、lngDRowsを使わずにUboundを使って処理を
しようと思ったのですが、さすがにそれは汚いコードかなと思って、
かといってそれぞれのシート用にlngDRows1、lngDCols2、lngDRows2、lngDCols2と
変数を増やすのもどうかなあと思って列数は同じようだと推測して提示のコードとなったのですが、
varTitleの貼り付けについては使いまわすつもりで組んでた時のまま修正漏れで投稿してしまいました。
 

回答
投稿日時: 17/12/20 22:03:30
投稿者: 二葉

もこな2さま、baooさま
帰宅してもこな2さまがkoikoi宛てに質問を立ててくれたはってとてもびっくりしました。
解決済にすると書き込むことができなくなるのですね。勝手に解決済にし申し訳ありませんでした。
 
感動したのと嬉しいので胸がいっぱいになりで涙と鼻水が止まりません。画面が見えません。
 
何の知識もなく、力になってくださろうとしている皆さんからの質問にも的確に答えられず、
いただいた教えにも反応できないkoikoiにイライラされたと思います。本当にありがとうございます。
しばらく、皆さんがアップしてくれはったマクロを見るだけで涙が出そうです。
 
もこな2さま、
>基本的に回答者は学ぶ(=自分で理解して作ろうという)気持ちがある質問者は大歓迎なので、
>ばしばし質問していいとおもいますよ。
ありがとうございます。もこな2さまのこの言葉に救われました。
koikoiやる気だけが空回りし全く成果が出ず、張り裂けそうでした。
11月の下旬からマクロに触れましたがワークシート関数との概念の違いに打ちのめされていました。
こちらのような質問サイトがあるのは知っていましたが、何もわかっていないkoikoiが質問をすることは皆さんの気分を害するかも知れない、と怖くて質問できませんでした。テキストを読んで、テキストの問題集のマクロを暗記して作れるようになっても、koikoiが作りたいものはできそうな光すら見えず行詰まっていました。
丁寧に教えてくれはっただけやなく、テキストよりも分かり易く説明していただき、ありがとうございます。
 
baooさま
>私の配列マクロですが、後半でカッコ悪い部分があります。
koikoiには全く分かりませんのでご安心ください。koikoiもっともっとVBAプログラミングの勉強をしてbaooさまが作ってくれはったマクロの恰好悪い部分に気付けるようになります。
>sheet1とsheet2では行数が違うはずですし、列数が違っている可能性も考えて
そこまで気が付くやなんて、すごいです。どんだけ想像力に長けてるんやろか。
 
こちらで教えていただいたマクロも気持ちが落ち着いたら大事に丁寧に勉強させていただきます。
koikoiは、いつかもこな2さんやbaooさん、mokutachiさんや細雪さん達のいたはるところに行きたいです。
本当に本当に感謝しています。ありがとうございます。
 
biさん、これからはマクロで考えつまづいた疑問、他ではなくこちらで連投することにします。
ご指摘ありがとうございました。
 
書いたマクロを検証してもらうべき場所で文章ばかりですみません。気持ちが収まりません。
皆様の知識と想像力に圧倒されました。
皆様のご親切とご協力に本当にどんな言葉でお礼を伝えれば良いのか、言葉が見つかりません。
皆様のお蔭でkoikoiはVBAというものにとても興味が持てました。
私もそこへ行きたいです。
本当にありがとうございます。
皆様の回答、とてもとてもとてもとても嬉しかったです。
 
koikoi5151

回答
投稿日時: 17/12/21 18:02:00
投稿者: 二葉

ありがとうございます。いただいたマクロ勉強させていただいています。
 
早速質問があります。
 
Dim objDIC As Object
Set objDIC = CreateObject("Scripting.Dictionary")
 
'===いったん、Sheet2のデータをA列(ID)をキーにして「objDIC」に格納
With ThisWorkbook.Worksheets("Sheet2")
    For i = 2 To .Cells(.Rows.Count, 1).End(xlUp).Row
        objDIC(.Cells(i, 1).Value) = _
            .Cells(i, "C").Value & "," & .Cells(i, "E").Value & "," & .Cells(i, "G").Value
    Next i
End with
 
上記箇所の
For i = 2 To .Cells(.Rows.Count, 1).End(xlUp).Row
の部分についてです。
一番下から見てデータのある最初のセルまで、
Cells(Rows.Count, 1).End(xlUp).Row
ではなく
 .Cells(.Rows.Count, 1).End(xlUp).Row △○△
とするのはどうしてですか。
 
△○△のCells、Rows前の"."は何を意味しているのですか。

回答
投稿日時: 17/12/21 18:10:30
投稿者: 二葉

続いての質問ですみません。
昨晩いただいたマクロを勉強しています。
 
シート名の間違いや連想配列範囲を超えているとは確認できないのですが、
実行すると
”実行時エラー'9'インデックスが有効範囲にありません。”
となり
モジュールのどこも黄色く塗りつぶされていません。
インデックスの有効範囲、何を確認すべきでしょうか。
 
昨晩こちらで教えていただいたマクロです。
よろしくお願いします。
↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓
フォルダオプションSub Sample3()
'===変数の宣言とか
Dim objDIC As Object
Set objDIC = CreateObject("Scripting.Dictionary")
Dim Mykey As Variant
Dim i As Long
 
 
'===いったん、Sheet2のデータをA列(ID)をキーにして「objDIC」に格納
With ThisWorkbook.Worksheets("Sheet2")
    For i = 2 To .Cells(.Rows.Count, 1).End(xlUp).Row
        objDIC(.Cells(i, 1).Value) = _
            .Cells(i, "C").Value & "," & .Cells(i, "E").Value & "," & .Cells(i, "G").Value
    Next i
End With
 
'===つぎに、Sheet1のデータでA列(ID)が「objDIC」に登録されていれば更新、
'===登録されていなければ「objDIC」に追加
With ThisWorkbook.Worksheets("Sheet1")
    For i = 2 To .Cells(.Rows.Count, 1).End(xlUp).Row
        objDIC(.Cells(i, 1).Value) = _
            .Cells(i, "C").Value & "," & .Cells(i, "E").Value & "," & .Cells(i, "G").Value
    Next i
End With
 
'===「objDIC」からkeyを、配列変数(一次)に取り出す
Mykey = objDIC.keys
 
'===「出力」へ出力
With ThisWorkbook.Worksheets("出力")
    For i = 1 To objDIC.Count
        .Cells(i + 1, "A").Value = Mykey(i - 1)
        .Range(.Cells(i + 1, "B"), .Cells(i + 1, "D")).Value = _
            Split(objDIC(Mykey(i - 1)), ",")
    Next i
End With
 
End Sub
の登録されている拡張子は表示しない、もチェックが入っています。

回答
投稿日時: 17/12/21 18:42:09
投稿者: 二葉

度々すみません。
本当に何度も恥ずかしいですがよろしくお願いします。
 
Mykeyは一次配列なので、0からなんですよね。
「出力」へ出力はCopyを使われていませんが、どちらのコードが出力となるのでしょうか。
 
'===「出力」へ出力
With ThisWorkbook.Worksheets("出力")
 
For i = 1 To objDIC.Count ←この時のiはobjDICに入れた行数を表しているということですか。
 
.Cells(i + 1, "A").Value = Mykey(i - 1) ←A列2行目にMykeyの1番目が入るということですか。
 
.Range(.Cells(i + 1, "B"), .Cells(i + 1, "D")).Value = _ ←すみません、ここの箇所が全く理解できません。B列2行目〜、D列2行目〜の値ということですよね。
 
 Split(objDIC(Mykey(i - 1)), ",") ← ここは2次元配列を配列に入れているので−1なのでしょうか。
 
何度も細かく質問してすみませんがよろしくお願いします。

回答
投稿日時: 17/12/21 18:53:53
投稿者: 二葉

.Range(.Cells(i + 1, "B"), .Cells(i + 1, "D")).Value = _
は、セル範囲指定に変数を使われているからですよね。
B列2行目〜B列の終わり行、D列2行目〜D列の終わり行、ということですよね。

投稿日時: 17/12/21 20:10:52
投稿者: もこな2

とりあえず、私に解る範囲で説明してみます。
ちょっと間違ってるかもしれないので他の回答者様のアドバイスも参考にしてみてください。

koikoi5151 さんの引用:
一番下から見てデータのある最初のセルまで、
Cells(Rows.Count, 1).End(xlUp).Row
ではなく
 .Cells(.Rows.Count, 1).End(xlUp).Row △○△
とするのはどうしてですか。
 
△○△のCells、Rows前の"."は何を意味しているのですか。
この部分を理解するには、オブジェクトの階層構造と、Withステートメントを学ぶ必要があります。
 
そもそも、オブジェクトとはよく使っているWowkbook とか、WorkSheet とか操作の対象になるものです。これらは実は階層仕立てになっていて
Application
 WorkBook
  WorkSheet
   Range
というように、親子関係があります。
そして、ExcelVBAの特徴として、上位オブジェクトは省略して記述出来るというものがあります。
ただし、省略した場合は、すべてアクティブなものを指定したという意味にExcel君は理解します。
なので、単純にCells(〜〜)とした場合、Excel君は
Application.ActiveBook.ActiveSheet.Cells(〜〜)と赤字の部分を勝手に追加して理解することになります。
これでも、ブックが1つしか開いてなくて、そのなかにシートが1つしかなければ、問題はないんですが、普通は複数のブックを開いていることもあるでしょうし、シートが2つ以上あるかもしれません。
そんなときに、他のブックや目的じゃないシートがアクティブのときに上位オブジェクトの記述を省略したマクロを実行してしまうと、Excel君は素直にアクティブなものに対して仕事をするので、ユーザーからみればそうじゃないよ!となってしまいます。
 
なので、操作対象がアクティブになってることが絶対に保証される状況じゃない限りは、上位オブジェクトの記述は省略すべきではないです。(技術的には省略できますが、思った動作になることが保証されませんし、記述的に問題ないからエラーにもならず、あとで原因不明の誤動作をするって悩むことになりかねません。)
 
ここまでが、オブジェクトの階層構造のお話です。
 
↓に続きます。(Withステートメント)

投稿日時: 17/12/21 21:07:33
投稿者: もこな2

さて、↑のとおり、操作したいオブジェクトがアクティブじゃない場合でもちゃんと動くようにするにはどうしたら良いでしょうか。
 
答えは簡単、操作するオブジェクトを明示することです。
これを踏まえて、「テスト.xls」の「シート1」の「A1」セルを選択するコードを書いてみましょう。

Application.Workbooks("テスト.xls").Worksheets("シート1").Range("A1").Select
とこうなります。
 
一般的には、さすがに他のアプリケーション(Excel以外のソフト)をいじってるときにエクセルのマクロを実行することはないとおもいますので、大抵はApplicationは省略して
Workbooks("テスト.xls").Worksheets("シート1").Range("A1").Select
って記述されることが多いようです。
 
さて、↑の場合は、まぁちょっと長くなった程度で済みましたが、
Cells(Rows.Count, 1).End(xlUp).Row
これをちゃんと書こうとするとどうなるでしょうか?※マクロが書いてあるブックの「Sheet2」の操作をしたい場合とします。

ThisWorkbook.Worksheets("Sheet2").Cells(ThisWorkbook.Worksheets("Sheet2").Rows.Count, 1).End(xlUp).Row
ちょっと長くなりましたね。
では「出力」のセル範囲である↓はどうでしょうか
Range(Cells(i + 1, "B"), Cells(i + 1, "D")).Value


ThisWorkbook.Worksheets("出力").Range(ThisWorkbook.Worksheets("出力").Cells(i + 1, "B"), ThisWorkbook.Worksheets("出力").Cells(i + 1, "D")).Value
間違っていないか心配になるくらい長くなりましたね。
 
こんな時に便利なのがWithステートメントです。
「With ThisWorkbook.Worksheets("Sheet2")」と記述した場合は、Excel君に「End With」って言うまで .〜〜って記述したらThisWorkbook.Worksheets("Sheet2")をくっつけて理解しなさい って命令することができます。
ただし、このとき気をつけていただきたいのが、先ほど説明した上位オブジェクトは省略可能だけど、省略した上位オブジェクトはアクティブなんちゃらだと理解されるという点です。
例をあげるならば、Sheet1がアクティブのときに、↓を実行すると
With ThisWorkbook.Worksheets("Sheet2")
   最終行= .Cells(.Rows.Count, 1).End(xlUp).Row '--@
  最終行= Cells(Rows.Count, 1).End(xlUp).Row '--A
End with

@では、Sheet2のセルのうち、Sheet2の一番下の行の1列目をクリックしてCtrl+↑ を押してカーソルがとまるセルの行を最終行として設定しなさいという意味になるのに対して
AではSheet1のセルのうち、Sheet1の一番下の行の1列目をクリックしてCtrl+↑ を押してカーソルがとまるセルの行を最終行として設定しなさいという意味に変わってしまいます。
 
ただ、この場合、「Rows.Count」は他のシートや他のブックでも基本的には同じ数のはずなので、ThisWorkbook.Worksheets("Sheet2")じゃなくて、アクティブなシートでも問題はないはずです。(実際、省略している例も少なくないです)しかし、個人的には、オブジェクトはちゃんと書くべきだなっていうように思っているので、わざとWithステートメントを使って「.Rows.Count」っていう記述をしています。
まぁこれは個人的な趣味ですね。。。ぇぇ
 
とりあず、オブジェクトの階層構造とWithステートメントについては、私はこんな感じにしか説明できないです。もうちょっと情報が欲しい場合は、適当に調べてみたり、諸兄姉の追加コメントをお待ち下さい。

投稿日時: 17/12/21 21:16:24
投稿者: もこな2

koikoi5151 さんの引用:
実行すると
”実行時エラー'9'インデックスが有効範囲にありません。”
となり
モジュールのどこも黄色く塗りつぶされていません。
インデックスの有効範囲、何を確認すべきでしょうか。
 
昨晩こちらで教えていただいたマクロです。
よろしくお願いします。
↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓
フォルダオプションSub Sample3()
  (中略)
の登録されている拡張子は表示しない、もチェックが入っています。
う〜ん これはどうしてだろう。
 
とりあえず、
>フォルダオプションの登録されている拡張子は表示しない、もチェックが入っています。
は関係ないです。
 
単なる打ち間違えだとはおもいますが、
フォルダオプションSub Sample3()
赤字の部分がほんとにコード上にあるんだったらこれが原因ですね
 
これでなければステップ実行(F8を押して1行ずつ実行)を試してみて、どこで、実行時エラーって出るか教えて下さい。

回答
投稿日時: 17/12/21 21:30:06
投稿者: 二葉

丁寧で理解できる説明をありがとうございます。
 
本やネットで階層とかクラスは読みましたがこのようにして使うんですね。
とても分かり易いです。
 
>普通は複数のブックを開いていることもあるでしょうし、シートが2つ以上あるかもしれません。
>そんなときに、他のブックや目的じゃないシートがアクティブのときに上位オブジェクトの記述を省略したマ>クロを実行してしまうと、Excel君は素直にアクティブなものに対して仕事をするので、ユーザーからみればそ>うじゃないよ!となってしまいます。
まさに、何度も何度も失敗したのは階層考えずに組んだものを実行していたからなんですね。
 
>操作するオブジェクトを明示する
ありがとうございます。
長いコードから省略されたコードを書いてくださり、とっても分かり易いです。
今日、ここの部分は理解できました。
 
ありがとうございます。
 
ずっと考えていたのですが、
.Range(.Cells(i + 1, "B"), .Cells(i + 1, "D")).Value = Split(objDIC(Mykey(i - 1)), ",")
このコードはB列2行目〜B列最終行からD列2行目〜D列最終行に配列のMykeyを代入している、ということですよね。
マクロの"=(イコール)"の考え方、難しいです。
そもそも i = i + 1 ←これ、同じ値じゃないですよね。
右=左は左右同じ値、同じ意味と考えていまい、コードを読んでいても意味が分からなくなります。
もっと沢山コードを読まないといけないですね。
 
ありがとうございます。
 

回答
投稿日時: 17/12/21 21:34:17
投稿者: 二葉

はっ!!!
すみませんでした。
>フォルダオプションSub Sample3()
>赤字の部分がほんとにコード上にあるんだったらこれが原因ですね
大変失礼しました。フォルダオプション、コードにありました。
気が付きませんでした。
勝手なkoikoioの間違いでした。
申し訳ございません。m(_ _)m

投稿日時: 17/12/21 21:48:13
投稿者: もこな2

koikoi5151 さんの引用:
Mykeyは一次配列なので、0からなんですよね。
「出力」へ出力はCopyを使われていませんが、どちらのコードが出力となるのでしょうか。
 
'===「出力」へ出力
With ThisWorkbook.Worksheets("出力")
For i = 1 To objDIC.Count ←この時のiはobjDICに入れた行数を表しているということですか。
.Cells(i + 1, "A").Value = Mykey(i - 1) ←A列2行目にMykeyの1番目が入るということですか。
.Range(.Cells(i + 1, "B"), .Cells(i + 1, "D")).Value = _ ←すみません、ここの箇所が全く理解できません。B列2行目〜、D列2行目〜の値ということですよね。
 Split(objDIC(Mykey(i - 1)), ",") ← ここは2次元配列を配列に入れているので−1なのでしょうか。

 
まとめて、
引用:
Mykeyは一次配列なので、0からなんですよね。
 これはちょっと違います。Variant型の変数である「Mykey」に連想配列であるobjDICのkeyの集まりであるKeys(配列)をえいやって入れたので0からスタートする1次配列になってます。
やり方次第で、1からスタートするようにも出来るんですが、複雑になっちゃうので今回はその方法は採用しませんでした。
 
引用:
objDIC.Count ←この時のiはobjDICに入れた行数を表しているということですか。
 当たらずとも遠からず。連想配列(objDIC)にデータが何個格納されているのかを調べてます。
 
引用:
 .Range(.Cells(i + 1, "B"), .Cells(i + 1, "D")).Value = ←すみません、ここの箇所が全く理解できません。B列2行目〜、D列2行目〜の値ということですよね。
  そうではないです。これは後回しにします。
 
引用:
Split(objDIC(Mykey(i - 1)), ",") ← ここは2次元配列を配列に入れているので−1なのでしょうか。

ちがいます。そもそも今回は2次元配列を使っていません。(セル範囲が2次元配列じゃないかというツッコミは置いとくとして・・・)
 
これは、Split関数を理解してないと解らないかもしれないです。
Split関数は、文字列と区切り文字を引数として与えてやると1次元配列に直してくれる関数です。(ちょっと曲解かもしれませんが)
そして、ちょっとうえの方に目を移すと
「.Cells(i, "C").Value & "," & .Cells(i, "E").Value & "," & .Cells(i, "G").Value」というところがあるとおもいますが、ここで、C列の値、E列の値、G列の値を「,(カンマ)」を挟みながら1つの文字列として連想配列(objDIC)のItem部に格納しています。
出力時には、これを「出力」のB〜D列に一気に出力したかったので、
「出力」のn行のB〜D列 に 1つの文字列 を 「,(カンマ)」で区切って(3つのデータが並んでいる状態にして)入れなさい っていう命令をしています。
 

投稿日時: 17/12/21 22:24:14
投稿者: もこな2

koikoi5151 さんの引用:
.Range(.Cells(i + 1, "B"), .Cells(i + 1, "D")).Value = _
は、セル範囲指定に変数を使われているからですよね。
B列2行目〜B列の終わり行、D列2行目〜D列の終わり行、ということですよね。
いい線ついてますけど違います。
 
これは、Rangeプロパティを使ったセル範囲の表現を勉強されるとよいかとおもいます。
 
よく見る方法として
Range("A1:D5").Select
というようなものがあるかとおもいます。
これを実行するとA1〜D5が選択されます。
 
しかし、セル範囲の表現はいくつかやり方があって、
Range(Range1、Range2)のRange1にセル範囲の左上になるセル、Range2にセル範囲の右下になるセルを記述するっていう方法もあります。
また、セルの表現にもRangeプロパティを使う方法のほかに、Cellsプロパティを使うって方法があるんです。
Range("A1") と Cells(1,1) はおなじものを指します。(実は、Rangeのほうは、RangeオブジェクトのなかのRangeプロパティなので・・・・って説明が必要な気もしますが、ここは私もよくわかってないので興味があったら頑張って自力学習してください。)
ちょっと話がそれました。
とにかく、セルの表現にはRangeのほかにCellsも使えるんです。
そして、Rangeオブジェクトにセルを2つ渡すとセル範囲という意味になるんです。(なんか説明になってないような気もしますが、、、まぁ別の回答者さんのフォロー待ちということで。。。)
ですので、
Range(.Cells(i + 1, "B"), .Cells(i + 1, "D")).Value
はセル範囲「(Bi)〜(Di)」という意味で使っていて、iは変数ですから、1例をあげると
i=2 のときは 「B2〜D2」の3つのセルのことを言っています。
 
さらに先ほどの説明のとおり、3つのセルには、Split関数で3つに区切ったデータをいれてね
という命令を、objDICに格納されてるデータの数だけ繰り返し実行しています。
 
さらに言えばこの繰り返し部分の
書き込みは2行目からスタートしているわけですから、
1個目のデータは2行目に
2個目のデータは3行目に
n個目のデータはn+1行目に出力させる必要がありますし、
 
Split関数で区切るための文字列を取り出すにはobjDICのkeyに対するItemを取り出す必要があり、Keyの集まりであるkeysを配列として受け取ったMyKeyは0からスタートしているので、
1個目のデータを取り出したいときは、Mykey(0)をキーにitemを呼び出す
2個目のデータを取り出したいときは、Mykey(1)をキーにitemを呼び出す
n個目のデータを取り出したいときは、Mykey(n−1)をキーにitemを呼び出す
ってことを ごちゃごちゃと やってます。
 
まぁ。。。解りづらいと思うので、前トピックでもコメントしましたけど、いきなり配列や連想配列を使った処理を勉強するのではなくて、基本というかベーシックな処理方法を知ってからでも遅くないかなぁ とおもいます。

回答
投稿日時: 17/12/21 23:10:18
投稿者: 二葉

ありがとうございます。
本当に分かり易いです。
ご丁寧な説明に本当に感謝しています。
本やネットよりもグンっとクリアになっています。
 
今日は2時間ほど時間があったので配列について読んで読んで書いてテストデータを実行して
結果を確認していました。
何となく理解できたように感じていたところなので、ご説明いただいてはっきりしました。
ありがとうございます。
(連想配列はまだ時間がかかりそうです。)
Splitは配列だと考えていました。
Splitは文字列をしていした区切り文字で区切って配列に入れるんですね。
 
>Rangeオブジェクトにセルを2つ渡すとセル範囲という意味になる
そういうことだったんですね!!!すっきりしました。
 
>Range(.Cells(i + 1, "B"), .Cells(i + 1, "D")).Value
>はセル範囲「(Bi)〜(Di)」という意味で使っていて、iは変数ですから、1例をあげると
>i=2 のときは 「B2〜D2」の3つのセルのことを言っています
そうなんですね。そうな動きをしているとは!!すごいや。
全くイメージできていませんでした。汗。
 
>objDIC.Count ←この時のiはobjDICに入れた行数を表しているということですか。
>当たらずとも遠からず。連想配列(objDIC)にデータが何個格納されているのかを調べてます。
この動きはびっくりです。"i"は行数にしか使わないと考えていました。
個数数えてる、て!!すごいです。
 
大変貴重な説明を沢山いただいて、ありがたいのと早く理解したいのとで
興奮して落ち着いて読めなくなってきました。
 
とてもとても丁寧にご説明くださいまして、本当にありがとうございます。
質問した何倍もの説明を書いてくださって相当なご負担だったと思います。
お時間を沢山回答に割いてくださいまして、ありがとうございます。
 
まだまだですが、もこな2様のお蔭で少しづつですがコードを読んで理解することが
楽しくなってきています。
まずはコードを読んで理解できるようになります。
そしたら、書いて、作れるようになるのを目標に進めていきます。
 
本当に本当にありがとうございます。

投稿日時: 17/12/22 00:19:14
投稿者: もこな2

koikoi5151 さんの引用:
マクロの"=(イコール)"の考え方、難しいです。
そもそも i = i + 1 ←これ、同じ値じゃないですよね。
右=左は左右同じ値、同じ意味と考えていまい、コードを読んでいても意味が分からなくなります。
もっと沢山コードを読まないといけないですね。
自分は、VBA以外のプログラミング言語を知らないのでなんとも言えないですが、VBAでは「=」を比較演算子にも代人演算子にも使いますので、混乱してしまうかもですね。 逆に算術的な意味では使わない(はず)なので比較演算子でなければ代入演算子だと思ってしまうとか・・・

投稿日時: 17/12/22 00:38:30
投稿者: もこな2

koikoi5151 さんの引用:
>objDIC.Count ←この時のiはobjDICに入れた行数を表しているということですか。
>当たらずとも遠からず。連想配列(objDIC)にデータが何個格納されているのかを調べてます。
この動きはびっくりです。"i"は行数にしか使わないと考えていました。
個数数えてる、て!!すごいです。
別の回答者さんの受け売りですが、大抵のオブジェクトにはCountプロパティがあるようです。
 
たとえば、
WorkBooks.Count なら、今開いてるブックの数がわかりますし
ActiveBook.WorkSheets.Count なら、アクティブブックのワークシート数
Range("A1:D5").Count なら、セル範囲に何個セルがあるのか などがわかります。
 
このへんは、いわゆる繰り返し(ループ処理)の記述をするときに、指定した回数繰り返すという条件に使ったりしますので、覚えておいて損は無いと思います。(セットでIndexプロパティも覚えておいた方がいい気もしますが、あんまり一気に勉強しても大変だと思うので、説明は割愛します。)

回答
投稿日時: 17/12/22 10:50:51
投稿者: 二葉

ありがとうございます。
まだ内容を熟読する時間ができていないですがゆっくり読ませていただきます。
 
今回は、教えていただいたコードに追加した際発生しているエラーについて質問です。
欲しいデータをA列〜M列
出力をA列〜M列に変えました。
 
koikoiがいただいたマクロに項目や範囲を追加して試したところ、
Sub Sheet1tosheet2comper()
最初のこの箇所が黄色く塗り潰されて
 
'===いったん、Sheet2のデータをA列(ID)をキーにして「objDIC」に格納
ThisWorkbook.Worksheets ("Sheet2")
このコードの”.Worksheets”の部分が白字になり、青く塗りつぶされて
 
「コンパイルエラー:プロパティの使い方が不正です」と表示されます。
なぜでしょうか。
 
下記がkoikoiが追加させてもらったコードです。
対象範囲理解したはずなのですが。。。。
 
よろしくお願いします。
 
□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□
'===いったん、Sheet2のデータをA列(ID)をキーにして「objDIC」に格納
ThisWorkbook.Worksheets ("Sheet2")
 
     For i = 2 To .Cells(.Rows.Count, 1).End(xlUp).Row
      
        objDIC(.Cells(i, 2).Value) = _
            .Cells(i, "B").Value & "," & .Cells(i, "C").Value & "," & .Cells(i, "D").Value & "," & .Cells(i, "E").Value _
    & "," & .Cells(i, "F").Value & "," & .Cells(i, "G").Value & "," & .Cells(i, "H").Value & "," & .Cells(i, "I").Value _
    & "," & .Cells(i, "J").Value & "," & .Cells(i, "K").Value & "," & .Cells(i, "L").Value & "," & .Cells(i, "M").Value
    Next i
End With
 
'===つぎに、Sheet1のデータでA列(ID)が「objDIC」に登録されていれば更新、
'===登録されていなければ「objDIC」に追加
 
With ThisWorkbook.Worksheets("Sheet1")
    For i = 2 To .Cells(.Rows.Count, 1).End(xlUp).Row
        objDIC(.Cells(i, 1).Value) = _
    .Cells(i, "B").Value & "," & .Cells(i, "C").Value & "," & .Cells(i, "D").Value & "," & .Cells(i, "E").Value _
    & "," & .Cells(i, "F").Value & "," & .Cells(i, "G").Value & "," & .Cells(i, "H").Value & "," & .Cells(i, "I").Value _
    & "," & .Cells(i, "J").Value & "," & .Cells(i, "K").Value & "," & .Cells(i, "L").Value & "," & .Cells(i, "M").Value
    Next i
End With
 
'===「objDIC」からkeyを、配列変数(一次)に取り出す
Mykey = objDIC.keys
 
'===「出力」へ出力
With ThisWorkbook.Worksheets("出力")
    For i = 1 To objDIC.Count
        .Cells(i + 1, "A").Value = Mykey(i - 1)
        .Range(.Cells(i + 1, "B"), .Cells(i + 1, "M")).Value = _
            Split(objDIC(Mykey(i - 1)), ",")
    Next i
End With
 
    Set objDIC = Nothing
End Sub
 
本当に何度もすみません。
何卒、よろしくお願いいたします。

投稿日時: 17/12/22 12:55:37
投稿者: もこな2

もとにしたコードと見比べてみてください。
意味がなく書いてあるものはない(はず)なので、削除するとコードの意味が変わってしまいます。
 
ヒント:W〇th ってどこにいきました?

投稿日時: 17/12/22 13:51:23
投稿者: もこな2

追加コメントです。
 
私見ですが、このトピックでのご質問を拝見すると、
・Dictionaryオブジェクト(連装配列)を使ったコードのご質問というよりは、VBAに関するご質問が多いこと、
・ご質問の内容がコードに関する質問ではなく、ご自身で改良するときの質問に変わってきてること
・何より、トピックのタイトルが追加コメントっぽく見えるので他の回答者に質問が来てることが伝わりづらいこと
等から新たに質問トピックを立てたほうがいいような気がします。
 
なお、新たにトピック立てる場合には、どこまで自分でやったのか、いじったコードを提示するとともに、元のコードの置き場としてこのトピックのURLを貼ったらわかりやすいんじゃないかと思います。
 
ご検討ください。

回答
投稿日時: 17/12/22 15:36:52
投稿者: 二葉

何度も何度もありがとうございます。
本当に感謝ですm(_ _)m

回答
投稿日時: 17/12/22 15:38:19
投稿者: 二葉

どうしてこんな単純なことに気がつかないのか。。。。
落ち着いてもっと勉強します。
ありがとうございます。

投稿日時: 17/12/26 20:44:10
投稿者: もこな2

閉じておきます