エクセルマクロで異なる文字列を配列に格納する方法

このQ&Aのポイント
  • エクセルで異なる文字列の配列を作成するためのマクロの作り方について説明します。具体的には、「Data」シートに格納されている文字列を「.」で区切り、異なる値のみを配列に格納する方法を解説します。
  • エクセルで異なる値のみを配列に格納するためには、Split関数を使用し、格納する文字列として重複を除外する処理を追加する必要があります。
  • 具体的なマクロの例を紹介すると、まず「Data」シートのデータを変数に格納し、ループ処理でSplit関数を使用して文字列を分割します。分割した結果を新たな配列に格納する際に、重複チェックを行い、重複の無い文字列のみを配列に追加します。最終的に、各要素が異なる値になった配列が作成されます。
回答を見る
  • ベストアンサー

マクロの作り方について

お世話になっております。 エクセルで次のようなテーブルの自動生成マクロを作成したいと考えておりますが、なかなかうまくいきません。 皆さまのお知恵を拝借いたしたく、お願いいたします。 「Data」シート、「Table」シートの2つのシートをエクセルに用意します。 「Data」シートには、200行2列のデータが予め入っています。 1列目にはaaa.F、aaa.W、aaa.R、bbb.F、bbb.W、bbb.Rといった形の文字列が延々と入っています。 2列目には数字のデータが入っています。 行いたいのは、まず1列目のデータを「.」で区切って、2つの配列「st」と「pr」に入れなおすことです。 ただ、単にsplitするだけですと、1列目のデータを分けた際に、 st=(aaa、aaa、aaa、bbb、bbb、bbb) pr=(F、W、R、F、W、R) といった形で同じ値が格納されますが、ダブっている文字ははじく様にしたいのです。 このため、例えばstについて、次のようなマクロを考えたのですが、これだとstをdebug.Print等で出力した際、一番最後のデータだけしか格納されていませんでした。 Dim C As Variant C = Worksheets("DATA").Range("A1:B65000") Dim D As Variant Dim i As Integer Dim st As Variant For i = 1 To 10 D = Split(C(i, 1), ".") If st <> D(0) Then st = D(0) Debug.Print (st)  ↑ここでstを出力している分には、aaa、bbb、cccとダブった文字を省いたすべてのデータが出力されます。 Else End If Next Debug.Print (st)  ↑ここでstを出力すると、最後のデータだけしか出力することができません。  st(3)等、特定の要素を出力しようとしてもできないようです。 stをvariant型にしていることが問題なのかもしれませんが、stをstring型のarrayで定義し、各要素ごとに入力すると、st(0)=aaa、st(1)=aaaといった形で同じ値のものも入ってしまいます。 異なった文字列だけ各要素に入力していくにはどのようにマクロを組めばよいのでしょうか?

質問者が選んだベストアンサー

  • ベストアンサー
  • imogasi
  • ベストアンサー率27% (4737/17068)
回答No.3

#2です。 もう一度私の手元のパソコンのデータで、下記を実行しましたが、エラーが出ず、うまく行くようです。 原因追及の前に、#1の回答のシートのデータを使うこと(質問者の実際のデータを使わず)で、下記を標準モジュールに貼り付けて(下記をコピペして、そっくりそのままで)、もう一度実行してみてもらえませんか。 実行前に、aaa.Fなどの間のカンマについて(A列ある行で漏れていないか)チェックしてみてください。 Sub test06() Dim st(10): Dim pr(10) x = 0: y = 0 Dim rng As Range Dim d As Variant lr = Worksheets("DATA").Range("A1000").End(xlUp).Row 'MsgBox lr '----- For i = 1 To lr 'MsgBox Cells(i, "A") d = Split(Cells(i, "A"), ".") 'A列各行セルのデータをスプリット '---st について For j = 1 To x If st(j) = d(0) Then GoTo p1 '探索終り Else '何もしない End If Next j '最終的にd(0)はst()に見つからず、配列に追加 x = x + 1 st(x) = d(0) p1: '---prについて For j = 1 To y If pr(j) = d(1) Then GoTo P2 '探索終り Else '何もしない End If Next j '最終的にd(0)はpr()に見つからず、配列に追加 y = y + 1 pr(y) = d(1) P2: '---次行データへ Next i '---処理終了 For i = 1 To x MsgBox "stの" & i & "=" & st(i) Next i For i = 1 To y MsgBox "prの" & i & "=" & pr(i) Next i End Sub すぐに思い当たるエラーが、みつけられずで、すみません。 結果をお聞かせください。

220F284
質問者

お礼

お手数おかけいたしまして申し訳ございません。 私のDataタブの中でイレギュラーなデータがあったのか、aaa.F、aaa.W等手入力で入れた10行程度のデータではご連絡いただいたコードで問題なく目的が達成できました。 何度もご連絡いただきまして誠にありがとうございます。 ここまでできれば、あとは自分でもできそうです。 こちらをベストアンサーとして閉めさせていただきたいと思います。 ありがとうございました。

その他の回答 (2)

  • imogasi
  • ベストアンサー率27% (4737/17068)
回答No.2

#1です。セルを中間記録域として使わず、Findも使わず、逐次比較(If)だけでやりました。 Sub test06() Dim st(10): Dim pr(10) '10は結果を見通して、適当に見積もること x = 0: y = 0  '最初の要素は、+1してから、セットするので、1からになります Dim d As Variant lr = Worksheets("DATA").Range("A1000").End(xlUp).Row 'データのある最終行探知 'MsgBox lr '----- For i = 1 To lr 'MsgBox Cells(i, "A") d = Split(Cells(i, "A"), ".") 'A列各行セルのデータをカンマでスプリット '---st について For j = 1 To x If st(j) = d(0) Then GoTo p1 'すでに存在するので探索終り Else '何もしない End If Next j '最終的にd(0)はst()に見つからず、配列に追加 x = x + 1 st(x) = d(0) p1: '---prについて For j = 1 To y If pr(j) = d(1) Then GoTo P2 'すでに存在するので探索終り Else '何もしない,配列次要素と比較へ End If Next j '最終的にd(0)はst()に見つからず、配列に追加 y = y + 1 pr(y) = d(1) P2: '---次行データへ Next i '---処理終了 For i = 1 To x MsgBox "stの" & i & "=" & st(i) Next i For i = 1 To y MsgBox "prの" & i & "=" & pr(i) Next i End Sub 後はst、prを配列化して、似たようなルーチンを繰り返さないようにする課題は あると思う。 上記は質問者がst、prと個別の配列の名前を付けていたので、それを尊重したもの。

220F284
質問者

お礼

面倒な依頼にご対応いただきまして誠にありがとうございます。 ご連絡いただきましたマクロでst(x)=d(0)の部分で「インデックスが有効範囲にありません」となってしまい、どうもdをd(0)あるいはd(1)と指定していることでエラーが出ているようなのですが、こちらはどのように指定したらよろしいでしょうか?

  • imogasi
  • ベストアンサー率27% (4737/17068)
回答No.1

本回答は、たとえば、G,H列を中間作業列で使います。 例データ A1:B8 aaa.F 12 aaa.W 23 aaa.R 45 bbb.F 65 bbb.W 43 bbb.Q 22 bbb.R 22 ccc.D 22 ーーー Sub test05() Dim st(10): Dim pr(10) x = 1: y = 1 Dim rng As Range Dim d As Variant lr = Worksheets("DATA").Range("A1000").End(xlUp).Row 'MsgBox lr '----- For i = 1 To lr 'MsgBox Cells(i, "A") d = Split(Cells(i, "A"), ".") 'A列各行セルのデータをスプリット '--- Set rng = Worksheets("DATA").Range("G:G").Find(what:=d(0)) If rng Is Nothing Then lg = Worksheets("DATA").Range("G1000").End(xlUp).Row Cells(lg + 1, "G") = d(0) st(x) = d(0) x = x + 1 End If '--- Set rng = Range("H:H").Find(d(1)) If rng Is Nothing Then lh = Worksheets("DATA").Range("H1000").End(xlUp).Row Cells(lh + 1, "H") = d(1) pr(y) = d(1) y = y + 1 End If Next i '--配列の-結果確認 'st = Range("G:G") 'ダメ For i = 0 To x - 1 MsgBox st(i) Next i For i = 0 To y - 1 MsgBox pr(i) Next i End Sub ーーー 結果 G:H列 aaa F bbb W ccc R Q D ーーー 配列にも、上記の確認でわかるように、st、prに結果はセットできてています。 ただし、本回答はFindを使う以上、G,H列は省けないやり方です。 このやり方は、ロジックを作り配列内だけでふるいにかけるより、コードが初等的で簡単で、わかりやすいと思っています。ReDimなどの問題も起こります。 ーー 配列のFilterなどやってみましたが、適当でないようです。既存のCCCに対しCも「存在する」、になるようだ。 夜遅いので、十分検討ができてません。配列のFindとか(多分不可)、セルから配列に入れるとか、など。

220F284
質問者

お礼

夜遅くに回答を考えていただきましてありがとうございます。 解説も分かりやすく書いていただきまして助かります。 "DATA"シートのGH列は使用する予定がないので、GH列を使用して問題ないのですし、後で消してしまえばよいのですが、取り扱うデータ量が多いので、できれば最終結果を配列に格納する所まではマクロ内で済ませたいと考えています。 もしマクロ内で納める方法がございましたらご教授いただけますと幸いです。

関連するQ&A

  • エクセルのマクロについて教えて下さい。

    エクセルのマクロについて教えて下さい。 Sub Ref() Dim ax As String Dim num As Integer, i As Integer Dim arr As Variant Dim tex As String Range("A1").Select ax = ActiveCell.Formula arr = Split(ax, ",") For i = 0 To UBound(arr) num = i + 1 Cells(num, 1).Value = arr(i) Next i For i = 1 To 10 ActiveCell.Offset(, 1).Select tex = ActiveCell.Formula Selection.Resize(num, 1).Select Selection.Formula = tex Selection.Resize(1, 1).Select Next i End Sub このマクロを10行ほどまで対応させたいです。 例として2行の表ですが、           A         B   C  D   E  F 1 C100,C101,C102,C103 aaa bbb ccc ddd eee 2 C104,C105,C106,C107 とうい表を、     A B  C  D   E   F 1 C100 aaa bbb ccc ddd eee 2 C101 aaa bbb ccc ddd eee 3 C102 aaa bbb ccc ddd eee 4 C103 aaa bbb ccc ddd eee 5 C104 aaa bbb ccc ddd eee 6 C105 aaa bbb ccc ddd eee 7 C106 aaa bbb ccc ddd eee 8 C107 aaa bbb ccc ddd eee という表にしたいです。 結合してから展開しようと考えたのですが 1列目の文字列の最後にカンマが無い場合、ある場合がありまして、 対応する事が出来ませんでした。 マクロ初心者なので教えてください。 よろしくお願いします。

  • マクロで重複データの削除

    過去ログを使っていろいろ試したのですが、うまくいかなかったので助言お願いします。 データ的には B列 C列 AAA 50 AAA 50 BBB 70 BBB 70 BBB 72 CCC 25 のようなデータあります。 これを「AAA」でC列のデータが同じやつはひとつにするということをやりたいのです。 B列 C列 AAA 50 BBB 70 BBB 72 CCC 25 のようになります。 B列第一優先にC列第二で並べ替えをして、過去ログ参照より、下のデータからループしてくというのを試したのですが、全部削除されてしまいます。 しかし、これでは並べ替えの場合によってはCの重複がおかしくなると思うので、B列参照したほうがいいのかな? 別シートに書き出しタイプでないやり方をしたいと思っています。お助けくださいよろしくお願いします。

  • エクセルのマクロ【複数検索&検索結果の合計】

    以下のように 【sheet1】にA列B列からなるデータにおいて A列の内容が同じものどうしのB列の値を合計し その結果の大きい順に並べて 【sheet2】に出力するマクロを 作りたいのですが、どうしたらよいかわかりません。 どなたかお分かりになる方いらっしゃいましたら 教えて頂きたくお願い致します。 【sheet1】   A列    B列 aaa 5 bbb 4 aaa 3 aaa 2 ccc 89 bbb 100 【sheet2】 A列 bbb 104 ccc 89 aaa 10

  • 複数の列を繋げてA列に入れたい VBA

    aaa aaa  bbb aaa  bbb  ccc aaa (A列にaaa、B列にbbb、C列にcccが入ってます) と言うデータがあるのですが 全てA列に入れて aaa aaabbb aaabbbccc aaa としたいです。 ・最終列は必ずしもCではないのです。(Dの場合もEの場合もある) ・最終行も変化します。 Sub 分かれてる列を繋げる() Dim Col As Long Dim Row As Long For Row = 1 To Range("a65536").End(xlUp).Row   For Col = 1 To Cells(Row, 256).End(xlToLeft).Column    Cells(Row, 1) = Cells(Row, 1) & Cells(Row, 2) & Cells(Row, 3)    Next Col Next Row End Sub をやってみましたが、 aaa aaabbbbbb aaabbbcccbbbcccbbbccc aaa となってしまい、 欲しい結果とは違くなってしまいます。

  • エクセル:セルの検索

    Sheet1のC~G列を検索し、 [AAA]が見つかれば「成功」、見つからなければ「失敗」と表示するコードを作りました。 (実際のコードでは、AAAが見つかったセルBBBの.Addressや.Valueを使いたいので「Set BBB」などという書き方をしています)   Dim AAA As String Dim BBB As Range Set BBB = Worksheets("Sheet1").Range("C:G").CurrentRegion.Find(What:=AAA, LookAt:=xlWhole) If BBB Is Nothing Then MsgBox "検索に失敗" Else MsgBox "検索に成功" End If このコードで、C~D列にAAAがある場合は見つかるのですが、 E~G列にAAAがある場合は見つからず「検索に失敗」とメッセージが出ます。 また、 別のシートでも全く同じコードを使っているのですが、こちらは正常に動作します。 上に挙げたコードと違うところは検索範囲がE~I列だというだけです。 上記コードでとあるシートにおいてのみE~G列にある値が検索に引っかからない理由として、 どのようなことが考えられるでしょうか。 保護はかかっていません。 値が微妙に違うということもありません。 大文字小文字、半角全角の指定はしておりませんが、 C列で検索に引っかかった値をそのままG列に移動しただけで見つからなくなります。 なお、AAAに入れているデータは、 Private Sub Worksheet_Change(ByVal Target As Range) End Sub のTarget.Addressで、「$A$20」のような形で入っています。 Sheet1のC~G列に用意している値も「$A$20」のような形で直接書き込んでいます。

  • Excel2002:複数条件のデータの個数の集計

    苦手な集計について質問させてください。 [A] [B] [1] AAA aaa [2] BBB bbb [3] AAA aaa [4] AAA bbb [5] BBB ccc 上記のようなデータで[A]と[B]のAND条件でみたときの個数を集計したいと思います。 例えば上記であれば、 [A]AAAかつ[B]aaa・・・2個 [A]BBBかつ[B]bbb・・・1個 [A]AAAかつ[B]bbb・・・1個 [A]BBBかつ[B]ccc・・・1個 になります。[B]のデータは[A]のデータに依存せず、[A]の各値にまたがっています。([B]bbbは[A]AAAと[A]BBBの場合があります) 実際のシートでは、全パターンを網羅したリストがA列とB列、集計対象がD列とE列にあります。 上記の例でいえば、以下のようになっています。 [A] [B] [C] [D] [E] [1] AAA aaa AAA aaa [2] AAA bbb BBB bbb [3] BBB bbb AAA aaa [4] BBB ccc AAA bbb [5] BBB ccc つまり[A]列と[B]列が組み合わせパターン、[D]列と[E]列が集計元データです。 ちなみにパターン数が414個、集計元データは29000個程度です。 そして最終的な各パターンの個数を[C]列に表示させたいと思います。 VLOOKUPやピボットテーブルを考えましたが、ピンと来ません。 適切なやり方を教えてください。よろしくお願いします。

  • こんにちは。

    こんにちは。 Excel VBA で別シートの特定列をセル参照させて、あたらしいシートを作成しています。 以下の方法で実現できてはいるのですが、行数が多く且つ20回以上(20列というべき?)も 同じ処理をさせているため、処理が3分近くかかって遅いことを気にしています。 (やりたいこと) ・参照元シート「AAA」の値を変更すれば、参照先シート「BBB」の表も自動的に書き換わるようにしたい。 ・AAAシートのデータ行数は各列とも同じだが、何行あるかは不定。 ・参照元、参照先の列関係(下の例で言えばAAAシートB列をBBBシートC列に、AAAシートY列をBBBシートD列に対応させる)は固定。 (現在のコード) 参照元シート「AAA」のB3~B5003のセル番地を、参照先シート「BBB」のC11~C5011に設定。 同様に、参照元シート「AAA」のY3~Y5003のセル番地を、参照先シート「BBB」のD11~D5011に設定。 同様に…(これを約20列分行なう) Dim maxRow As Long, n as Long maxRow = 5003 ' 実際には関数を使って取得します。 For n = 3 To maxRow ' AAAシートB3~B5003 → BBBシートC11~C5011 Cells(8 + n, 3).Formula = "=AAA!B" + n ' AAAシートY3~Y5003 → BBBシートD11~D5011 Cells(8 + n, 4).Formula = "=AAA!Y" + n '  : '  以下同様の処理がおよそ20列続きます。 Next n 値コピーではなく参照式を一括で埋め込む方法や、別の手段で参照式の設定を高速化させる うまい方法をご存知の方、ご教授いただけませんでしょうか。

  • エクセルのマクロについて質問です。

    下の表を展開したいです。    A   B   C  D  E  F  G 1 C102,C103,C104 aaa bbb ccc ddd~ 2 R102,R103,R105 YYY RRR EEE GGG~ 3 R106,R107,R108   空白(上と同じ) 4 空白 5 L102,L103,L105 QQQ MMM NNN BBB~ という表を、 1 C102 aaa bbb ccc ddd 2 C103 aaa bbb ccc ddd 3 C104 aaa bbb ccc ddd 4 R102 YYY RRR EEE GGG というように最後まで展開していきたいです。 下のマクロだとB列以降が全て一番上と同じ文字列がコピーされてしまいます。 よろしくお願いします。 Sub test2() Dim ax As String 'A列のセルに入っているテキストを代入するための変数 Dim ax2 As String 'axを統合したテキストを代入するための変数 Dim num As Integer, i As Integer '回数を代入するための変数 Dim arr As Variant '配列を格納 Dim tex As String 'B列以降の文字列を代入するための変数 'A列にいくつデータが入っているかを確かめ、その数をnumに代入 Range("A1").Select Selection.CurrentRegion.Select num = Selection.Rows.Count Range("A1").Select 'A1のテキストの最後にカンマが入っているかを判定。なければカンマをつける。 'A列のデータが入っている最後のセルまで上記の処理を行う。 '各テキストは変数axに代入、ax2で統合する For i = 1 To num ax = ActiveCell.Text If Right(ax, 1) = "," Then ax = ax Else ax = ax & "," End If If i = 1 Then ax2 = ax Else ax2 = ax2 & ax End If ActiveCell.Offset(1).Select Next i ax2 = Left(ax2, Len(ax2) - 1)  arr = Split(ax2, ",") Range("A1").Select For i = 0 To UBound(arr) num = i + 1 Cells(num, 1).Value = arr(i) Next i Range("A1").Select Selection.CurrentRegion.Select num = Selection.Rows.Count 'B~D列を展開 For i = 1 To 3 ActiveCell.Offset(, 1).Select tex = ActiveCell.Formula Selection.Resize(num, 1).Select Selection.Formula = tex Selection.Resize(1, 1).Select Next i End Sub

  • マクロでhtml出力?

    先日、マクロの件で質問した者です。 http://oshiete1.goo.ne.jp/qa4473686.html 良回答のlulさんのコードを参考にしています。 質問1 下記のコードではV列にhtmlが表示されるようになっています。 (エクセルにはAからTまでデータが入っています) 今回はセルV列にhtmlを表示するのではなくエクセルシートが置いてあるフォルダに各htmlを出力したいのですがどこをどのように変更すればいいのでしょうか? (ちなみに、C列にあるものをファイル名とします) 質問2 また、フォルダ名を指定してそのフォルダに出力する場合も教えてください。 よろしくお願いします。 Sub htmlを作成() Const LFeed As String = vbCrLf Dim st As String Dim sht As Worksheet, i As Long, obj Set sht = ActiveSheet '//現在のシートを設定 Dim MaxRow As Long MaxRow = Range("A65536").End(xlUp).Row For i = 1 To MaxRow If Cells(i, 1) <> "" Then Set Grammar = Nothing 'HTML1行ずつ記載 st = "" st = st & "<html lang='ja'>" & LFeed st = st & "<head>" & LFeed st = st & "</head>" & LFeed st = st & "<body>" & LFeed 途中省略 st = st & "</body>" & LFeed st = st & "</html>" & LFeed st = Replace(st, "'", Chr(34), 1, -1, 1) sht.Cells(i, 22).Value = Mid(st, 1, Len(st) - 1) '//結果を V列に入れる(他の場合はそのように変更する) End If Next i End Sub

  • Variant型で宣言してるのにEmptyになる

    エクセルVBA2003について質問です。 Sub aaa1() Dim a As Variant Debug.Print TypeName(a) End Sub を実行してイミディエイトウインドウで確認すると Emptyが返ってきます。 Variantが返ってこない理由は何でしょうか? また、変数の方の宣言をしない場合は Variant型になるはずなのに Sub aaa2() Dim a Debug.Print TypeName(a) End Sub を実行すると、同じくEmptyが返ってきます。 Variantが返らない理由を教えてください。よろしくお願いします。

専門家に質問してみよう