[[20240124010351]] 『マクロで条件ごとに文字を合体する』(難しい) ページの最後に飛ぶ

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

 

『マクロで条件ごとに文字を合体する』(難しい)

教えてください。
下記のような表があります。
やりたい事は、まずA列の名前を「;」で区切って合体して、その結果をA1セルに書きたいです。
Aさん;Bさん;Cさんとなる。

次に、C列の分類がaの行のB列の文字も「;」で合体して、A1セルにさらに合体したい。
A1セルの結果を、「Aさん;Bさん;Cさん;Dさん;Gさん;Hさん」としたい。
それぞれ単独には出来たのですが、両方を合体するにはどうすればいいかを教えて欲しいです。
また、別案でもっとシンプルなコードがあればぜひ教えてください。

あと、A列合体マクロの方ですが、下記事例の場合は正しく動くのですが、
もし3行目に1つだけ文字があって4行目以降空欄の場合(つまり合体するものが1つしかない)と、

    dataArr = Range("A3:A" & lastRow).Value の部分で型が一致しませんと出ます。
更に、3行目以降全て空欄の場合、なぜかA1セルにはき出される結果は「名前」と書かれます。これらも解決しつつ、B列の条件にあう文字も合体する方法が分かれば教えて欲しいです。

   A列   B列   C列
 1
 2 名前	  名前	  分類
 3 Aさん  Dさん	   a
 4 Bさん  Eさん	   b
 5 Cさん  Fさん	   c
	  Gさん  a
	  Hさん	   a
	  Iさん	   b

Sub A列合体マクロ()

    Dim lastRow As Long
    Dim dataArr() As Variant
    Dim concatString As String
    Dim i As Long

    ' A列の最終行を取得
    lastRow = Cells(Rows.Count, 1).End(xlUp).Row

    ' A列のデータを配列に読み込み
    dataArr = Range("A3:A" & lastRow).Value

    ' 文字列を合体
    For i = 1 To UBound(dataArr, 1)
        If Not IsEmpty(dataArr(i, 1)) Then
            If concatString <> "" Then
                concatString = concatString & ";" & dataArr(i, 1)
            Else
                concatString = dataArr(i, 1)
            End If
        End If
    Next i

    ' 結果をA1セルに書き込む
    Range("A1").Value = concatString
End Sub	   

Sub B列合体マクロ()

    Dim lastRow As Long
    Dim dataArr() As Variant
    Dim concatString As String
    Dim i As Long

    ' A列の最終行を取得
    lastRow = Cells(Rows.Count, 2).End(xlUp).Row

    ' A列とB列のデータを配列に読み込み
    dataArr = Range("B3:C" & lastRow).Value

    ' 文字列を合体
    For i = 1 To UBound(dataArr, 1)
        If Not IsEmpty(dataArr(i, 2)) And dataArr(i, 2) = "a" Then
            If concatString <> "" Then
                concatString = concatString & ";" & dataArr(i, 1)
            Else
                concatString = dataArr(i, 1)
            End If
        End If
    Next i

    ' 結果をA1セルに書き込む
    Range("A1").Value = concatString
End Sub

< 使用 Excel:Microsoft365、使用 OS:Windows10 >


コードを読む時間がないので、とりあえず数式案です。

 E2 =TRANSPOSE(TEXTJOIN(";",TRUE,A3:A8,FILTER(B3:B8,C3:C8="a","")))

    |[A]  |[B]  |[C] |[D]|[E]                                
 [1]|     |     |    |   |                                   
 [2]|名前 |名前 |分類|   |Aさん;Bさん;Cさん;Dさん;Gさん;Hさん
 [3]|Aさん|Dさん|a   |   |                                   
 [4]|Bさん|Eさん|b   |   |                                   
 [5]|Cさん|Fさん|c   |   |                                   
 [6]|     |Gさん|a   |   |                                   
 [7]|     |Hさん|a   |   |                                   
 [8]|     |Iさん|b   |   |                                   
(フォーキー) 2024/01/24(水) 01:33:13

数式版、ありがとうございます!!
このように取得できるのですね。とても勉強になります。

今回は一連のマクロの中で再現したいと思っているので、
引き続き、マクロの方もよろしくお願いします。
(難しい) 2024/01/24(水) 05:52:16


 1. A3しかない場合への対応
    姑息な手段かもしれないが、
    dataArr = Range("A2:A" & lastRow).Value
    と2行目から範囲にして、
    For i = 2 To UBound(dataArr, 1)
    としたらどうですか?

 2.両者の統合
    Function プロシージャにして、結果だけを文字列結合したらどうですか?
    こんな感じです。
    Sub test()
        Dim s1 As String, s2 As String
        s1 = A列合体マクロ
        s2 = B列合体マクロ("a") '判定要素は引数で受け渡します
        If s1 <> "" Then
            If s2 <> "" Then
                Range("A1") = s1 & ";" & s2
            Else
                Range("A1") = s1
            End If
        Else
            Range("A1") = s2
        End If
    End Sub

  3. ちなみに、A3がブランクといったエッジケースもあるなら、以下のようにします。

      ' A列の最終行を取得
      lastRow = Cells(Rows.Count, 1).End(xlUp).Row
      If Range("A3") = "" Then Exit Function    ' ←←■
      ' A列のデータを配列に読み込み
      dataArr = Range("A2:A" & lastRow).Value
      ' 文字列を合体
      For i = 2 To UBound(dataArr, 1)

  実際のコードは、そちらでトライしてください。考え方が明らかなら、できるかと思います。  

(xyz) 2024/01/24(水) 06:52:48


 いくつか作ってみました。

 1 数式をマクロ化(A列が空欄、B列対象なしでも動く)
 Sub test()
     Dim r As Long
     r = Range("A2").CurrentRegion.Rows.Count
     With Range("A1")
         .Formula = "=TRANSPOSE(TEXTJOIN("";"",TRUE,A3:A" & r & ",FILTER(B3:B" & r & ",C3:C" & r & "=""a"","""")))"
         .Value = .Value
     End With
 End Sub

 2 A列をJoin関数で結合(A列に名前が2件以上ない場合は考慮してない)
 Sub test2()
     Dim buf As String, r As Long, i As Long
     r = Cells(Rows.Count, "A").End(xlUp).Row
     buf = Join(Application.Transpose(Range("A3", Cells(r, "A"))), ";")
     For i = 3 To Cells(Rows.Count, "B").End(xlUp).Row
         If Cells(i, "C") = "a" Then buf = buf & ";" & Cells(i, "B")
     Next
     Range("A1") = buf
 End Sub

 3 ベタベタに1件ずつ結合
 Sub test3()
     Dim r As Long, i As Long, buf As String
     r = Cells(Rows.Count, "A").End(xlUp).Row
     If r > 2 Then
         For i = 3 To r
             buf = buf & ";" & Cells(i, "A")
         Next
     End If
     r = Cells(Rows.Count, "B").End(xlUp).Row
     If r > 2 Then
         For i = 3 To r
             If Cells(i, "C") = "a" Then buf = buf & ";" & Cells(i, "B")
         Next
     End If
     Range("A1") = Mid(buf, 2)
 End Sub
(フォーキー) 2024/01/24(水) 06:59:59

xyz様
ありがとうございます。
Function、挑戦してみます!

フォーキー様
ありがとうございます。
数式織り込みや、1件ずつ結合も分かりやすいです。参考にさせて頂きます。
(難しい) 2024/01/24(水) 07:12:03


発想を変えて、配列に1つずつ格納していってはどうですか?
    Sub 別案1()
        Dim 行 As Long, c As Long
        Dim 配列() As String

        With ActiveSheet
            For 行 = 3 To .Cells(.Rows.Count, "A").End(xlUp).Row
                ReDim Preserve 配列(c)
                配列(c) = .Cells(行, "A").Value
                c = c + 1
            Next 行

            For 行 = 3 To .Cells(.Rows.Count, "B").End(xlUp).Row
                If .Cells(行, "C").Value = "a" Then
                    ReDim Preserve 配列(c)
                    配列(c) = .Cells(行, "B").Value
                    c = c + 1
                End If
            Next
        End With

        If (Not 配列) <> -1 Then
            MsgBox Join(配列, ";")
        Else
            MsgBox "該当無し"
        End If
    End Sub

もちろん、1つの【文字列】でも可能です。(フォーキーさんの3と同じですが)

    Sub 別案2()
        Dim 行 As Long, c As Long
        Dim 文字列 As String

        With ActiveSheet
            For 行 = 3 To .Cells(.Rows.Count, "A").End(xlUp).Row
                文字列 = 文字列 & .Cells(行, "A").Value & ";"
            Next 行

            For 行 = 3 To .Cells(.Rows.Count, "B").End(xlUp).Row
                If .Cells(行, "C").Value = "a" Then
                    文字列 = 文字列 & .Cells(行, "B").Value & ";"
                End If
            Next
        End With

        If 文字列 <> "" Then
            MsgBox Left(文字列, Len(文字列) - 1)
        Else
            MsgBox "該当無し"
        End If
    End Sub

(もこな2 ) 2024/01/24(水) 12:50:33


追加の質問で恐縮ですが、教えてください。
そして、もこな2様、お返事遅くなりすみません。確認しました。ありがとうございました。
皆さまのおかげで、分類が「a」の場合はできて、次に、bの場合、cの場合もやりたいです。
今回は分類がa,b,cの3分類ですが、実際はもっと多くなります。
もこな2様のコードを使って、a, bを作業しようとすると下記のように長くなってしまいました。
これをもっとシンプルにするにはどうすればいいか教えて欲しいです。
例えば、Dim 行 やDim配列() や、Dim c 等は2回目もそのまま書くと宣言の重複になってしまうので、
行2, 配列2(), c2としたら動きましたが、これを1つにうまくまとめる方法があれば教えて欲しいです。

    Sub Test()
        Dim 行 As Long, c As Long
        Dim 配列() As String
        With ActiveSheet
            For 行 = 3 To .Cells(.Rows.Count, "A").End(xlUp).Row
                ReDim Preserve 配列(c)
                配列(c) = .Cells(行, "A").Value
                c = c + 1
            Next 行
            For 行 = 3 To .Cells(.Rows.Count, "B").End(xlUp).Row
                If .Cells(行, "C").Value = "a" Then
                    ReDim Preserve 配列(c)
                    配列(c) = .Cells(行, "B").Value
                    c = c + 1
                End If
            Next

            If (Not 配列) <> -1 Then
                .Cells(1, "A").Value = Join(配列, ";")
            Else
                MsgBox "該当無し"
            End If
        End With

        Dim 行2 As Long, c2 As Long
        Dim 配列2() As String
        With ActiveSheet
            For 行2 = 3 To .Cells(.Rows.Count, "A").End(xlUp).Row
                ReDim Preserve 配列2(c2)
                配列2(c2) = .Cells(行2, "A").Value
                c2 = c2 + 1
            Next 行2
            For 行2 = 3 To .Cells(.Rows.Count, "B").End(xlUp).Row
                If .Cells(行2, "C").Value = "b" Then
                    ReDim Preserve 配列2(c2)
                    配列2(c2) = .Cells(行2, "B").Value
                    c2 = c2 + 1
                End If
            Next

            If (Not 配列2) <> -1 Then
                .Cells(1, "B").Value = Join(配列2, ";")
            Else
                MsgBox "該当無し"
            End If
        End With
    End Sub
(難しい) 2024/01/25(木) 23:41:17

 面白そうなので参加!
    Option Explicit
    Sub 実行プロシジャ()
        Debug.Print "A列で空白以外:"; UDF_JOINIF([a3], [a3], "", False, ";")
        Debug.Print "C列がaの場合B列を結合:"; UDF_JOINIF([b3], [c3], "a", True, ";")
        Debug.Print "C列がbの場合B列を結合:"; UDF_JOINIF([b3], [c3], "b", True, ";")
        Debug.Print "C列がcの場合B列を結合:"; UDF_JOINIF([b3], [c3], "c", True, ";")
        Debug.Print "C列がzの場合B列を結合:"; UDF_JOINIF([b3], [c3], "z", True, ";")
    End Sub

    'ユーザー関数
    Function UDF_JOINIF(ByVal join_range As Range, ByVal criteria_range As Range, ByVal criteria As String, include As Boolean, dlm As String) As String
        Dim f As String
        Dim r1 As Range
        Dim r2 As Range
        Dim v As Variant

        '検索条件 完全一致がそれ以外のみ 以上、以下は未対応(Evaluate用の式)
        If include Then
            f = "=transpose(if(★=""▲"",■,char(2)))"
        Else
            f = "=transpose(if(★<>""▲"",■,char(2)))"
        End If

        '結合範囲の設定 例題のA3以降が空白の場合でも、A3以降のみしか取得しない
        Set r1 = Intersect(join_range.Resize(Rows.Count - join_range.Row), Range(join_range(1), Cells(Rows.Count, join_range.Column).End(xlUp)))

        '検索範囲の設定 結合範囲とサイズを合わせる
        Set r2 = criteria_range(1).Resize(r1.Rows.Count)

        'Evaluate用の式の組み立て
        f = Replace(f, "■", r1.Address)
        f = Replace(f, "★", r2.Address)
        f = Replace(f, "▲", criteria)

        'Evaluateを実行して、結果を配列で受け取る
        v = Application.Evaluate(f)

        '一致しない条件を削除
        v = Filter(v, Chr(2), False)

        '配列を結合して出力
        UDF_JOINIF = Join(v, dlm)
    End Function
(稲葉) 2024/01/26(金) 10:08:18

 あえて Functionプロシージャ(この場合は、Sub プロシージャでもOKですが)を使うこともできる、
 という例を示しておきます。
 下記のtestプロシージャから、getDataプロシージャを呼び出しています。

 なお、getDataに相当する部分が長大なものであったりする場合は特に、
 主たるプロシージャーの流れが見えにくくなるので、
 こうしたFunctionプロシージャ(やSubプロシージャ)を使うとよいでしょう。
 ただ今回のような比較的短い場合は、下記のtest2のように書いてしまうと思います。
 どちらも同じ結果が得られます。

 なお、他のプロシージャへの引数の渡し方にも注目して下さい。
 デフォルトだとByRefが省略されていると解釈されるので、いわゆる"参照渡し"です。
 配列やその大きさを示す変数cを、親と子で共有することになります。
 このあたりは、VBAのテキストなどに詳しく説明されているはずです。よく復習してみてください。

 Sub test()
     Dim 行 As Long, c As Long
     Dim 配列()  As String
     Dim s  As Variant

     With ActiveSheet
         For 行 = 3 To .Cells(.Rows.Count, "A").End(xlUp).Row
             ReDim Preserve 配列(c)
             配列(c) = .Cells(行, "A").Value
             c = c + 1
         Next 行
         For Each s In Array("a", "b", "c")
             Call getData(s, 配列, c)
         Next
         .Cells(1, "A").Value = Join(配列, ";")
     End With
 End Sub

 Function getData(s As Variant, 配列() As String, c As Long)
     Dim 行 As Long
     With ActiveSheet
         For 行 = 3 To .Cells(.Rows.Count, "B").End(xlUp).Row
             If .Cells(行, "C").Value = s Then
                 ReDim Preserve 配列(c)
                 配列(c) = .Cells(行, "B").Value
                 c = c + 1
             End If
         Next
     End With
 End Function

 Sub test2()
     Dim 行 As Long, c As Long
     Dim 配列()  As String
     Dim s     As Variant

     With ActiveSheet
         For 行 = 3 To .Cells(.Rows.Count, "A").End(xlUp).Row
             ReDim Preserve 配列(c)
             配列(c) = .Cells(行, "A").Value
             c = c + 1
         Next 行

         For Each s In Array("a", "b", "c")
             For 行 = 3 To .Cells(.Rows.Count, "B").End(xlUp).Row
                 If .Cells(行, "C").Value = s Then
                     ReDim Preserve 配列(c)
                     配列(c) = .Cells(行, "B").Value
                     c = c + 1
                 End If
             Next
         Next
         .Cells(1, "A").Value = Join(配列, ";")
     End With
 End Sub

 別法としては、
 ・A列の名前、
 ・B:C列を分類を優先キーにしてソートしたものを、
 名前が同一列になるように配置し、
 それに対して名前列を一次元配列にしたうえでJoinを取る、
 などといった方法もあるでしょう。
(xyz) 2024/01/26(金) 12:14:53

    Sub main()
    Dim c As Range, r As Range
    Rows(1).ClearContents
    If Range("C3").Value = "" Then Exit Sub
    Set r = Range("A1")
    For Each c In Range("C3:C" & Rows.Count).SpecialCells(2)
        If WorksheetFunction.CountIf(Range("C3:C" & c.Row), c.Value) = 1 Then
            r.Value = "=TEXTJOIN("";"",TRUE,FILTER($B$3:$B$" & Rows.Count & ",$C$3:$C$" & Rows.Count & "=C" & c.Row & ",""""))"
            r.Value = WorksheetFunction.TextJoin(";", True, Range(Range("A3"), Range("A" & Rows.Count).End(xlUp))) & ";" & r.Value
            Set r = r.Offset(, 1)
        End If
    Next c
    End Sub

(mm) 2024/01/26(金) 13:07:19


皆さま、大変ありがとうございます。返事が遅くなり申し訳ありません。

稲葉様のコードでは、ユーザー関数にこのように定義できるのですね。
ありがとうございます。難しくてまだ理解できていませんが、一つずつ分解して調べてみます。

mm様のコードでは、関数で出来てしまうのですね。家のPCが365対応でないからか?エラーが出てしまうのでまた後日試してみます。ありがとうございます。

xyz様、引数の渡し方のご説明まで、ありがとうございます。今ちょうど引数や配列等を勉強中なので、大変参考になります。
すみません質問の仕方がよろしくなかったですが、結果はA1セルにa,b,cのケースを全てまとめるのではなく、
aの場合は合体したものをA1セルに、bの場合は合体したものをB1セルに、Cの場合はC3セルに…と条件ごとに結果を表示したいです。
下記の場合、
A1セルには条件aの場合「Aさん;Bさん;Cさん;Dさん;Gさん;Hさん」
B1セルには条件bの場合「Aさん;Bさん;Cさん;Eさん;Iさん」
C1セルには条件dの場合「Aさん;Bさん;Cさん;Fさん」
としたいです。

xyz様のコードの「For Each s In Array("a", "b", "c")」の部分を
If s = "a" then
のように書けないかとかいろいろ試したものの上手く再現できず。。。引き続きアドバイス頂けますと助かります。

   A列   B列   C列
 1
 2 名前	  名前	  分類
 3 Aさん  Dさん	   a
 4 Bさん  Eさん	   b
 5 Cさん  Fさん	   c
	  Gさん  a
	  Hさん	   a
	  Iさん	   b

(難しい) 2024/01/26(金) 23:11:01


書きためている間に話しが進んでいますが投稿しておきます。

■1
>次に、bの場合、cの場合もやりたいです。
そういう話であれば、【文字列】で考えた方がシンプルかもしれません。
その場合、A列から取得する処理は1回だけにするということも可能です。

また、"a"の部分が"b"や"c"に変わればよく、それ以外は使い回しできるので、分類の数だけB列の処理を書かなくても大丈夫です。

■2
上記を踏まえると↓のようなことでもよいと思います。

    Sub 別案2_改()
        Dim 行 As Long, c As Long
        Dim 分類 As Variant
        Dim A列文字列 As String, B列文字列 As String

        With ActiveSheet
            For 行 = 3 To .Cells(.Rows.Count, "A").End(xlUp).Row
                A列文字列 = A列文字列 & .Cells(行, "A").Value & ";"
            Next 行

            B列文字列 = A列文字列
            For Each 分類 In Array("a", "b", "c", "d")
                B列文字列 = A列文字列
                For 行 = 3 To .Cells(.Rows.Count, "B").End(xlUp).Row
                    If .Cells(行, "C").Value = 分類 Then
                        B列文字列 = B列文字列 & .Cells(行, "B").Value & ";"
                    End If
                Next 行

                If B列文字列 <> "" Then
                    MsgBox "【分類 " & 分類 & " で抽出】" & vbLf & Left(B列文字列, Len(B列文字列) - 1)
                Else
                    MsgBox "【分類 " & 分類 & " で抽出】" & vbLf & "該当無し"
                End If

            Next 分類
        End With
    End Sub

 ※1 上記は説明のための提示であり、完成品プレゼントの意図はありません。
 ※2 採用される場合は【ステップ実行】等により研究の上、理解できてから必要な部分のみご自身のコードに組み込んでください。

■3
>これをもっとシンプルにするには
何をもってシンプルとするか難しいところですが、上記の処理でいえばB列の処理を外だしにするという手はあると思います。

    Sub 別案2_改二()
        Dim 行 As Long
        Dim 文字列 As String

        With ActiveSheet
            For 行 = 3 To .Cells(.Rows.Count, "A").End(xlUp).Row
                文字列 = 文字列 & ";" & .Cells(行, "A").Value
            Next 行

            MsgBox "【分類 a で抽出】" & vbLf & Mid(文字列 & B列処理("a"), 2)
            MsgBox "【分類 b で抽出】" & vbLf & Mid(文字列 & B列処理("b"), 2)
            MsgBox "【分類 c で抽出】" & vbLf & Mid(文字列 & B列処理("c"), 2)
            MsgBox "【分類 d で抽出】" & vbLf & Mid(文字列 & B列処理("d"), 2) 'A列にデータが無いとかっこ悪いので注意
        End With
    End Sub
    '============================================
    Function B列処理(分類 As String) As String
        Dim 行 As Long
        Dim 文字列 As String

        With ActiveSheet
            For 行 = 3 To .Cells(.Rows.Count, "B").End(xlUp).Row
                If .Cells(行, "C").Value = 分類 Then
                    文字列 = 文字列 & ";" & .Cells(行, "B").Value
                End If
            Next 行
        End With

        B列処理 = 文字列
    End Function

 ※こちらも研究素材として提供します。丸パクリして完成!というのはご遠慮ください。

■余談
話が飛躍しますが分類の数だけ処理をしたいということならば、まずはC列から重複のないリストを作成することを考えればよいでしょう。
混乱するとよろしくないのでリンク紹介に留めます。

 【リンク】
http://officetanaka.net/excel/vba/tips/tips80.htm

(もこな2 ) 2024/01/26(金) 23:20:11


度々すみません。下記のようにしてCallで呼んでみましたら一応できました。使い方として、合っていますか?

Sub Test()

    Call ProcessData("a", "A")
    Call ProcessData("b", "B")
    Call ProcessData("c", "C")
End Sub

Sub ProcessData(targetValue As String, targetColumn As String)

    Dim 行 As Long, c As Long
    Dim 配列() As String
    With ActiveSheet
        For 行 = 3 To .Cells(.Rows.Count, "A").End(xlUp).Row
            ReDim Preserve 配列(c)
            配列(c) = .Cells(行, "A").Value
            c = c + 1
        Next 行
        For 行 = 3 To .Cells(.Rows.Count, "B").End(xlUp).Row
            If .Cells(行, "C").Value = targetValue Then
                ReDim Preserve 配列(c)
                配列(c) = .Cells(行, "B").Value
                c = c + 1
            End If
        Next

        If (Not 配列) <> -1 Then
            .Cells(1, targetColumn).Value = Join(配列, ";")
        Else
            MsgBox "該当無し"
        End If
    End With
End Sub

(難しい) 2024/01/26(金) 23:22:06


もこな2様
ありがとうございます!!デバックで内容確認してみました。
1つめのコードは、ループの考え方がとても勉強になりました。

2つ目のコードのような分解方法もあるのですね。
自分のやりたい事を実現するにはどのようなフローでやるのかを、しっかりイメージして作れるかが重要ですね。そこが出来ていないので、意識していきたいと思います。
リンクのご提示もありがとうございます。
dictionaryもまだ勉強できていないので、引き出し増やしていければと思います。
(難しい) 2024/01/26(金) 23:40:10


 この仕様で自分が作成するならというのを作成してみました。
 参考になれば幸いです。

 汎用性を考慮して下記の2つの関数を作成します。

 指定したセル範囲のテキストを連結する関数 JoinRng
 (365なら TextJoin で代用可能)

 指定したセル範囲の条件に一致したテキストを連結する関数 JoinIf

 Public Function JoinRng(sourceRange As Range, delimiter As String) As String
    Dim i As Long
    For i = 1 To sourceRange.Cells.Count
        JoinRng = JoinRng & delimiter & sourceRange.Cells(i)
    Next
    JoinRng = Mid(JoinRng, 2)
 End Function

 Public Function JoinIf(sourceRange As Range, criteriaRange As Range, criteria, delimiter As String) As String
    Dim i As Long
    For i = 1 To sourceRange.Cells.Count
        If criteriaRange.Cells(i) = criteria Then
            JoinIf = JoinIf & delimiter & sourceRange.Cells(i)
        End If
    Next
    JoinIf = Mid(JoinIf, 2)
 End Function

 Public Sub Test()
    Dim r1 As Range, r2 As Range
    Set r1 = Range("A3", Cells(Rows.Count, "A").End(xlUp))
    Set r2 = Range("B3", Cells(Rows.Count, "B").End(xlUp))

    Dim s, c As Range
    Set c = Range("A1") '出力起点セル
    For Each s In Split("a b c")
        c = JoinRng(r1, ";") & ";" & JoinIf(r2, r2.Offset(, 1), s, ";")
        Set c = c.Offset(,1)
    Next
 End Sub

(hatena) 2024/01/27(土) 04:54:12


hatena様
朝早くからありがとうございます!
今、デバックしながら解読していました。
理解が追い付いていませんが、すごいですね。
双方を関数にしてしまえば、汎用性が持てますね。ありがとうございます。

一つ教えてください。
関数の方もSubの方も先頭にPublicが付いていますが、これ取ってしまっても動きます。
実際は他の工程の中にこの処理を組み合わせたいです。
同じモジュール内にいくつかのFunctionやSubを組み合わせる場合、Dim等の設定もSubの更に上に置いて外に置いた方がいいのかとか、Publicを使うのがいいのかとか、その辺がネットでしらべるも実際の使いどころがいまいち分からず、、、

(難しい) 2024/01/27(土) 06:37:38


 Publicを付けると、他のモジュールからも参照できます。
 対して、Privateを付けるとそのモジュールでしか参照できません。
 これはそのモジュールでしか使わない、あるいは使わせたくないプロシージャにつけます。
 他にFriendというのもありますが、これはちょっと高度だし使う機会はほとんどないので、
 興味があったら調べてみてください。

 今回は汎用性を考慮してますので、どこからでも使えるように Public にしてます。

 で、これらの宣言を省略すると Public として扱われます。
 ですので、これを取ってしまっても同様に動きます。

(hatena) 2024/01/27(土) 10:05:32


 Publicは省略してもPublic扱いになるので、Privateにしたい場合以外は省略でいいでしょう。

 私の場合は、たいていAlt+I+Pでプロシージャの追加ダイアログから追加しますので、
 その時に自動でPublicはついてきますので、わざわざ削除はしないです。
(hatena) 2024/01/27(土) 10:43:28

hatena様
大変分かりやすいご説明、ありがとうございました。理解しました。
Friendも調べてみます!
(難しい) 2024/01/27(土) 11:29:52

>Dim等の設定もSubの更に上に置いて外に置いた方がいいのか

上記部分は、変数の適用範囲に関することだと思うので、
主題は違いますが、以下が参考になるかも。
[[20220924005855]]『モジュールレベルでの宣言』

変数の適用範囲
http://officetanaka.net/excel/vba/variable/05.htm

第108回.変数の適用範囲(スコープ,Private,Public)
https://excel-ubara.com/excelvba1/EXCELVBA408.html

(横から失礼) 2024/01/27(土) 12:22:51


参考リンク、ありがとうございます。
まさに、知りたかったものでした。
ちゃんと目的を考えて、使えるようになりたいと思います。
ありがとうございました。
(難しい) 2024/01/27(土) 12:39:43

コメント返信:

[ 一覧(最新更新順) ]


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