[[20200911164510]] 『担当者毎にシートわけしたい』(しのみや) ページの最後に飛ぶ

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

 

『担当者毎にシートわけしたい』(しのみや)

 14時30分頃に質問させてもらったのですが、
 未のマークがつかなかったので、再度質問させてもらいます
 (私の不手際だったらすみません)

 教えてください
 【元データ1】
 ○Dataシート
   A    B   C
 1 
 2 
 3 番号  商品  担当者
 4 100  りんご  A
 5 230  トマト  B
 6 280  いちご  B
 7 350  メロン  C
 8 390  もも   A
 9 410  なし   A
   ↓
 最終行は可変
 【やりたいこと】
 担当者毎のシートを作成し、その担当者の人の行のみ貼り付ける
 【希望の結果】
 ------------------------
  ○Aシート
   A    B   C
 1 
 2 
 3 番号  商品  名前
 4 100  りんご  A
 5 390  もも   A
 6 410  なし   A
 ------------------------
  ○Bシート
   A    B   C
 1 
 2 
 3 番号  商品  名前
 4 230  トマト  B
 5 280  いちご  B
 ------------------------
  ○Cシート
   A    B   C
 1 
 2 
 3 番号  商品  名前
 4 350  メロン  C
 ------------------------
 【考えたこと】
 オートフィルタで絞り込んで、それぞれのシートに貼り付けるとか…
 マクロの記述にしようとするとどうもパッとしないというか…
 よい方法があったら教えてください

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


>マクロの記述にしようとするとどうもパッとしないというか…
どの部分が希望と異なるのですか?

現状のアプローチで大体良いようにおもいますが、ループ処理と組み合わせたいということであれば

 (1)作業用のシートを追加する
 (2)[Dataシート]のA3〜A列最終行までを,(1)のA1セルに貼り付ける
 (3)(2)に対して「重複の削除」を実行し、重複のないリストを作成する
 (4)[作業用シート]のA2〜A列最終行までセルの値を検索値として

 (5)[Dataシート]にオートフィルタを設定し3列目が検索値であるものを抽出
 (6)[Dataシート]のオートフィルタが設定されている範囲をコピー
 (7)[検索値 & "シート"シート]のA3セルに貼付

 (8)作業シートを削除

のようにしてみてはどうでしょうか?
この方法であれば、ループ処理の部分を除き、大体の必要な命令は【マクロの記録】でしらべることができるとおもいます。
肝心のループ処理については、過去の質問を振り返れば答えがみつかるんじゃないですかね。

(もこな2 ) 2020/09/11(金) 17:08


 こんばんは!
方法は沢山あると思います。
私風に書いてみました。。。
良かったら参考にしてください。。。
では、、、では、、、

 Option Explicit
Sub てすと()
Dim MyA As Variant
Dim x As Variant
Dim y() As Variant
Dim z As Variant
Dim v As Variant
Dim MySh As String
Dim i As Long
Dim j As Long
Dim n As Long
ReDim y(0)
ReDim z(0)
With Sheets("元データ1")
    MyA = .Range("A3").CurrentRegion.Resize(, 3).Value
    For i = LBound(MyA, 1) + 1 To UBound(MyA, 1)
        If Not Evaluate("=ISREF('" & "○" & MyA(i, 3) & "'!A1)") Then Sheets.Add.Name = "○" & MyA(i, 3)
        x = Application.Match(MyA(i, 3), z, 0)
        If IsError(x) Then
            ReDim Preserve y(n)
            ReDim Preserve z(n)
            y(n) = .Range("A3").Resize(, 3).Value
            z(n) = MyA(i, 3)
            n = n + 1
        End If
    Next
    For i = LBound(MyA, 1) + 1 To UBound(MyA, 1)
        x = Application.Match(MyA(i, 3), z, 0)
        If Not IsError(x) Then
            v = Application.Transpose(y(x - 1))
            ReDim Preserve v(LBound(v, 1) To UBound(v, 1), LBound(v, 2) To UBound(v, 2) + 1)
            For j = LBound(MyA, 2) To UBound(MyA, 2)
                v(j, UBound(v, 2)) = MyA(i, j)
            Next
            y(x - 1) = Application.Transpose(v)
        End If
    Next
End With
For i = LBound(y) To UBound(y)
    v = y(i)
    MySh = "○" & v(UBound(v, 1), UBound(v, 2))
    With Sheets(MySh)
        .Cells.Clear
        .Range("A3").Resize(UBound(v, 1), UBound(v, 2)).Value = v
    End With
Next
Erase MyA, y, z, v
End Sub
(SoulMan) 2020/09/11(金) 18:01

 もこな2さん ありがとうございます

 おっしゃるようにマクロの記録とループで作れると思いますので
 今までそうやって作ってきたのですが…
 この質問箱で教えて頂くと、毎回新しい発見があるので質問させて頂きました

 (下記に頂いたSoulManさんの記述を読ませてもらって思っていることなのですが)
 おそらくマクロの記録では、セル範囲の設定が固定(という表現はおかしいかもですが)ですので、
 そのあたりの私の勉強が足りないのかなと考えています

 SoulManさん ありがとうございます

 頂いた記述を読ませてもらっておりまして、まだ途中までしか理解できていないのですが…
 わからない点があり、もしお時間よければ教えて下さい

 1
       MyA = .Range("A3").CurrentRegion.Resize(, 3).Value は、
    MyA = .Range("A3").CurrentRegion だけでも問題ないと思うのですが、
    理由がなにかあるのでしょうか?

 2
         If IsError(x) Then
             ReDim Preserve y(n)
             ReDim Preserve z(n)
             y(n) = .Range("A3").Resize(, 3).Value
             z(n) = MyA(i, 3)
             n = n + 1
         End If
    既にシートがなければ、担当者毎のシートを作成の流れで
    上記の記述は何をしているのでしょうか?
(しのみや) 2020/09/14(月) 11:03

 こんばんは!
めちゃくちゃレスポンスが悪くて本当に申し訳ございません。
昼間は、おかげさまでめ〜〜いっぱい働いていますのでIphoneを見る余裕もありません。m(__)m

 さて、お問い合わせの 1 ですが、
MyA = .Range("A3").CurrentRegion
だけでも問題ないといえば問題ありません。
でも、次のステートメントでインデックスの 3 を使用しますから
必ずデータは3列分あって欲しいのです。
意図からすると、1つでも二つでもだめ、、必ず三つ欲しい。。。
かつ、4つ以上はあってもいらない。。。という書き手の意図です。

 次に、ご質問の 2 です。
これは、配列を使って各シートに振り分けたいのですが、
いくつ配列が必要なのかわかりませんよね?
つまり担当者が何人いらっしゃるかわからないので
空の配列を一つ作って担当者ごとに格納していきます。
その際に、二次元の配列を取得していきます。
この様な配列を 多段配列 とか ジグザグ配列 というそうです。(あまり詳しくありません。m(__)m)
y(n)(i,j)
こんなイメージです。。。

 最近、お問い合わせが続きますので緊張しております。。です。。。
私みたいな我流コードでも参考にして頂けたら幸いです。

 では、、では、、また。。。
(SoulMan) 2020/09/14(月) 19:55

>>どの部分が希望と異なるのですか?
残念ながら↑の答えが返ってきませんでしたが、例えば↓のようなコードを書いた場合、★のところはマクロの記録でどのような命令を使えばよいのかアタリは付けられたと思いますけどねぇ・・・
    Sub テキトー()
        Dim 作業シート As Worksheet
        Dim i As Long
        Dim 最終行 As Long

        Stop

        Worksheets.Add before:=Worksheets(1) '★
        Set 作業シート = Worksheets(1)

        With Worksheets("Data")
            .AutoFilterMode = False
            .Range("C3:C" & .Cells(.Rows.Count, "A").End(xlUp).Row).Copy 作業シート.Range("A1")
        End With

        With 作業シート
            .Range("A1", .Cells(Rows.Count, "A").End(xlUp)).RemoveDuplicates Columns:=1, Header:=xlYes '★
            最終行 = 作業シート.Cells(Rows.Count, "A").End(xlUp).Row
        End With

        With Worksheets("Data")
            For i = 2 To 最終行
                .Range("A3").AutoFilter Field:=3, Criteria1:=作業シート.Cells(i, "A").Value '★
                .AutoFilter.Range.Copy Worksheets(作業シート.Cells(i, "A").Value).Range("A3")
            Next
        End With

        Application.DisplayAlerts = False
        作業シート.Delete '★
        Application.DisplayAlerts = True

    End Sub

(もこな2) 2020/09/15(火) 04:09


 SoulManさん ありがとうございます

 お忙しいところ教えてくださり助かります
 ひとつひとつ調べているので、重箱の隅をつつくような質問になっていたらすみません…

 質問1 了解しました
 明示的に記述をしているのですね

 質問2
 私が作るとLoopで配列変数に +1して入れていくことが多いので、
 多段配列が使いこなせるようになれるといいな…頑張ります

 勉強になりますm(_ _)m

 質問ばかりですみませんが…
 マクロの記録をすると、このようには記述されないと思うのですが、
 何か別の言語から入られたのでしょうか?

 もこな2さん ありがとうございます

 >>どの部分が希望と異なるのですか?
 異なってはいませんです

 私もマクロの記録を使って書くと、
 書いて頂いた記述にたどり着いていると思います

 私の「パッとしない」という書き方が悪かったのですが、

 同じ動きなのに、多段配列を使って書かれている記述?は全然違って見えていて
 どうしたら自分もそのように書けるんだろうと勉強したいなと思いました
 (もやもやを言語化できておらず、後付けで申し訳ないです)

 もこな2さんが書いてくださった記述はすごく見やすい書き方ですし、
 メンテナンスもしやすそうです

(しのみや) 2020/09/15(火) 10:11


>私の「パッとしない」という書き方が悪かったのですが、
>同じ動きなのに、多段配列を使って書かれている記述?は全然違って見えていて
>どうしたら自分もそのように書けるんだろうと勉強したいなと思いました

"多段配列"という言葉は耳慣れませんが、たぶんジャグ配列のことですよね。
話があまり飲み込めませんが最初の投稿の時点で当該を使った処理の学習をしたかったということでしょうか。
ジャグ配列について、私は説明出来るほど詳しくありませんが、このサイトでも当該についていくつかコメントを見かけたことがありますので、過去ログを読んでみるのも良いかもしれません。

ちなみに、私の提示した方法は、重複のないリストを得るために作業シートをにコピーしてから重複の削除をしているわけですが、連想配列(Dictionaryオブジェクト)等を使ってメモリ上だけでリストを作ることは可能です。
最初に提示しなかったのは、メモリ上だけで処理されてしまうのでなかなかステップ実行して観察しづらいとおもったので避けた次第です。
重複しないリストの作成について興味があれば↓を読んでみると理解しやすいとおもいます。

 【Office TANAKA】
http://officetanaka.net/excel/vba/tips/tips80.htm

最後に、連想配列を使った例など提示しておきます。

    Sub テキトー2()
        Dim i As Long
        Dim objDIC As Object
        Set objDIC = CreateObject("Scripting.Dictionary")
        Dim リスト As Variant

        With Worksheets("Data")

            '連想配列で重複しないリストを作る
            On Error Resume Next
            For i = 4 To .Cells(.Rows.Count, "C").End(xlUp).Row
                objDIC.Add .Cells(i, "C").Value, .Cells(i, "C").Value
            Next i
            On Error GoTo 0

            'ここで重複のない1次元の配列をゲット
            リスト = objDIC.Keys

            'オートフィルタを強制解除する
            .AutoFilterMode = False

            For i = 0 To UBound(リスト)

                '抽出する
                .Range("A3").AutoFilter Field:=3, Criteria1:=リスト(i)

                'コピペする
                .AutoFilter.Range.Copy Worksheets(リスト(i)).Range("A3")
            Next i

            'オートフィルタを強制解除する
            .AutoFilterMode = False

        End With
    End Sub

(もこな2 ) 2020/09/15(火) 13:26


 こんばんは!
 >何か別の言語から入られたのでしょうか?
どうなんでしょうね???よく覚えていませんが、Excelしかしらないのでそれはないですね
昨夜気になって調べてみましたら、多段階配列 と 階 が入るのですね(^^;
自分が使っている配列の呼び方も知らないとはお粗末ですね(如何に検索していないかですね)

 私たちのころはこんなサイトやインターネットなんてのはありませんでしたから。。。
ほんとどうやって覚えたんでしょうね???20年は言い過ぎでも15〜17年くらい前なら普通に使ってましたからねぇ
でも、ローカルウィンドウの + をクリックするとy(1)(1,2)なんて構造はよく見かけるでしょ?
まぁ、普通にあるもんなんですよ

 私は、実務派ですから業務に追われて必然的に身についたんでしょうね?上司様のおかげで(笑)
ご自身の使いやすいメンテしやすいコードにされたらいいですよ。
せっかく書いても使われないコードは悲しいですから、、、でも、引き出しは多いほうがいいかな???

 あっ、以前も書きましたがコードを解読するときは印刷するといいですよ。
エディターというかぁ、、画面だけではやっぱりだめで全体を呑み込むにはやっぱりペーパーがいいと思います。
蛍光ペンや落書きも出来ますしね。

 もうお後がよろしいようで、、、頑張ってください。。。

 では、、では、、 また。。。
(SoulMan) 2020/09/15(火) 19:56

dictionaryには、こんな使い方も
(オートフィルタがわかりやすくて好きですが)

 Sub test()
    Dim dic As Object
    Dim v
    Dim i As Long
    Dim 担当者 As String
    Dim k

    Set dic = CreateObject("scripting.dictionary")

    v = Worksheets("元データ1").Range("A3").CurrentRegion.Value

    For i = 2 To UBound(v)
        担当者 = v(i, 3)
        If Not dic.exists(担当者) Then
            Set dic(担当者) = CreateObject("scripting.dictionary")
            dic(担当者)(0) = Application.Index(v, 1)
        End If
        dic(担当者)(dic(担当者).Count) = Application.Index(v, i)
    Next

    For Each k In dic.keys
        If Not Evaluate("isref('" & k & "'!A1)") Then
            Worksheets.Add.Name = k
        End If
        With Worksheets(k).Range("A3")
            .CurrentRegion.ClearContents
            .Resize(dic(k).Count, 3).Value = Application.Index(dic(k).items, 0)
        End With
    Next

 End Sub

(マナ) 2020/09/15(火) 20:18


最近は、オートフィルタよりも、フィルタオプションを好んで使用しています。

 Sub test2()
    Dim tbl As Range
    Dim c As Range
    Dim 担当者 As String

    Set tbl = Worksheets("元データ1").Range("A3").CurrentRegion

    Set c = tbl(1).Offset(, tbl.Columns.Count + 1)
    tbl.Columns(3).AdvancedFilter xlFilterCopy, , c, True

    Do While c(2).Value <> ""
        担当者 = c(2).Value
        c(2).Formula = "=""=" & 担当者 & """"
        If Not Evaluate("isref('" & 担当者 & "'!A1)") Then
            Worksheets.Add.Name = 担当者
        End If

        tbl.AdvancedFilter xlFilterCopy, c.Resize(2), Worksheets(担当者).Range("A3:C3")
        c(2).Delete xlShiftUp
    Loop

    c.Clear

 End Sub

(マナ) 2020/09/15(火) 20:23


最後に。と言っておきながらですが、よく考えれば1次元の配列に入れる必要なかったです。
ということで、修正しておきます。(もう見てないかもですが・・・)
    Sub テキトー2_改()
        Dim i As Long, 担当者 As Variant
        Dim objDIC As Object: Set objDIC = CreateObject("Scripting.Dictionary")

        With Worksheets("Data")
            On Error Resume Next
            For i = 4 To .Cells(.Rows.Count, "C").End(xlUp).Row
                objDIC.Add .Cells(i, "C").Value, ""
            Next i
            On Error GoTo 0

            .AutoFilterMode = False
            For Each 担当者 In objDIC.Keys
                .Range("A3").AutoFilter Field:=3, Criteria1:=担当者
                .AutoFilter.Range.Copy Worksheets(担当者).Range("A3")
            Next 担当者
            .AutoFilterMode = False
        End With
    End Sub

(もこな2) 2020/09/16(水) 12:27


Sub main()
    Dim c As Range
    For Each c In Sheets("Data").Range("C4:C" & Rows.Count).SpecialCells(2)
        Call shtexists(c.Value)
        Sheets(c.Value).Range("A3:C3").Value = Array("番号", "商品", "名前")
        Sheets(c.Value).Range("A" & WorksheetFunction.CountIf(c.EntireColumn.Resize(c.Row), c.Value) + 3).Resize(, 3).Value = c.Offset(, -2).Resize(, 3).Value
    Next c
End Sub
Function shtexists(arg)
    Dim temp
    On Error GoTo ere
    temp = Sheets(arg).Range("A1").Value
    GoTo skp
ere:
    Sheets.Add(after:=Sheets(Sheets.Count)).Name = arg
skp:
End Function

(mm) 2020/09/16(水) 16:55


 > 【やりたいこと】
 > 担当者毎のシートを作成し、その担当者の人の行のみ貼り付ける

 > 【考えたこと】
 >オートフィルタで絞り込んで、それぞれのシートに貼り付けるとか…
 >マクロの記述にしようとするとどうもパッとしないというか…
 >よい方法があったら教えてください

えっと、
例えば、オートフィルターの機能で、

▼をクリック
 ↓
選択肢をクリック
 ↓
抽出されたものが表示される

という操作と

シート毎に抽出してあったとして、

シートタブクリック
 ↓
抽出してあったものが表示

と、なるわけですが、
結局は、やりたいことを
「見たいデータを、見たいときに表示」が出来れば、
裏でどのようなことをやっていようが使う人は関係ないわけです。

で、マクロを使えば(オートフィルタを使うも含む)、元のデータさえあれば、
瞬時に意図したものが表示ができるので、
「事前に分けておく」必要がない上に、
データが2重に存在するということになり、
好ましくないなと思う反面、
何かを選択するという操作で、
「タブを選択」するという操作は、なかなか使い勝手がよい
(手動のオートフィルターの操作は、なんだか不評で教えても使ってもらえない)
のも事実です。
また、フィルターオプションという機能でも抽出は出来ますが、
手動でやると、たいていエラーが出て使い方が難しいですが、
マクロで書くとすごく短いコードになり便利です。

ということで、
各担当者のシートをクリックしたときに、
そのシート名をキーワードに、フィルターオプションを使って、そのシートに抽出してくる。
というような仕組みを作ることにチャレンジしてみてはいかがでしょうか?
欲しい結果を得る、手順を洗練させていくのもありかと思いました。

(まっつわん) 2020/09/16(水) 20:05


 もこな2さん ありがとうございます
 自分でも整理できておらず、ふわふわした質問ですみません
 連想配列…というものがあるのですね 修正のマクロもありがとうございます
 勉強になります
 自分が足りていない部分の入口が見えたような気がします

 SoulManさん ありがとうございます
 Excelから始められてこんな風にかけるのですね
 私の記述はマクロの記録とLoopだったりで…動いてはいますが、
 改善の余地ありですので、頑張ります

 マナさん ありがとうございます
 同じ動作でも、マクロにするとこんなに違うのですね
 全体の行数もずいぶん変わりますし…

 mmさん ありがとうございます
 デバッグして勉強させてもらいます

 シート分割は自分が扱えそうなマクロを活用させてもらいたいと思いますが、
 いろんなパターンの書き方を頂きありがとうございます
 理解が深まるように、動きを確認していきたいと思います
 今すぐには時間が取れないので、後から確認させてもらいます

 まっつわんさん ありがとうございます
 シート分けをしているのは、シートわけしたファイルを担当者全員にお渡しして
 自分のシートを見てもらうという流れが決まっておりまして
 担当者は確認だけで何かの操作は必要なく、閲覧のみのファイル(マクロがついたファイルを渡さない)の方が良いと
 今回は考えております
 幅広い知識を頂きありがとうございます
(しのみや) 2020/09/17(木) 11:13

余談にて失礼します。

"ジグザグ配列"と言う言葉が出てきましたが、これは一般的ですか?
"jagged array"に相当する日本語のようですが、余り聞いたことがなかったです。
"ジャグ配列"と言う言葉のほうが一般的な気がしました。

(ネット検索すると、とある英語サイトを翻訳したものの中での使用例がトップに表示されます。
翻訳ではない形で使われているのは、ちょっと見あたら無かったですね。
一般に使われるものなのでしょうか。
なお、Googleの機械翻訳は、"ギザギザ配列"と翻訳しますけど、これもちょっと怪しい。
jaggedの意味にはギザギザというものがあるようですけど。一要素ではなく配列なのでギザギザなのか?)

いずれにせよ,Variant型の配列であれば、なんでも突っ込めるわけですから、
便利は便利ですね。他の言語でも使われると思います。
特に気軽にpush,popなどをする使い方を併用すると便利と言えば便利です。

(γ) 2020/09/17(木) 11:51


 こんばんは!
 >"ジグザグ配列"と言う言葉が出てきましたが、これは一般的ですか?
どうなんでしょうね?
ジグザグ配列で検索すると割と上の方に出てくるのが↓こちらの方が書かれてるサイトですが、
https://riptutorial.com/ja/vba/example/16563/%E3%82%B8%E3%82%B0%E3%82%B6%E3%82%B0%E9%85%8D%E5%88%97-%E9%85%8D%E5%88%97%E3%81%AE%E9%85%8D%E5%88%97-
ぱっと見ですけど、配列の配列という記述が私的にはしっくりときました。
逆に私は、ジャグ配列というのを初めてではないでしょうけど聞きました。

 元々、私は多段配列という呼び方をしていましたのでこれは私の 階 の見落としでしょう
私はコードから入って呼び方が後からついてきた感がありますので最初にジグザク配列という呼び方を聞いたときは
「変なの」と思った記憶はあります。(笑)

 どこで見たかはほんと記憶にございません。。。

 余談ついでに校長先生にお願いがあります。
雑談部屋といいますか、コミュニティーBOXといいますか、、放課後のHRいたいな部屋があるといいなと思いました。
とは言え、校長先生のご負担も増えるでしょうからどこかの片隅にでも置いていただけたら幸いです。
(SoulMan) 2020/09/17(木) 19:26

こちらの掲示板でもジャグ配列というのが過去使われているようですね。
10回以上は登場しています。

引用されたサイトは、有名なStack Overflowという質問掲示板によるまとめ記事のようで
海外のサイトを各国版に翻訳したものですね。日本の方が翻訳しているものではないかも。

その記事の中でさえ、
・ギザギザ配列
・ジグザグ配列
・ジャグ配列
・ジャグド配列
・Jagged Array
などと色々な訳し方がされています。
訳語の統一ができていないので、用語については少なくとも余り信用できないんじゃないかと思います。
機械翻訳そのままか、少し手を入れたくらいのものでしょう。
(むろん英語ではjagged Arrayで一貫してますけど。)

(γ) 2020/09/17(木) 21:22


 日本語も様々で多段配列と紹介されているサイトもあるようですね。
https://smdn.jp/programming/netfx/arrays/1_multidimensional/
(SoulMan) 2020/09/17(木) 22:04

そのようですね。どうもありがとうございました。

以下、そちらから引用。
| 多次元配列は通常の配列(1次元配列)の次元を拡張したもので、マトリックスやグリッド、
| テーブルの様な矩形の構造を持ったデータ構造であることから、矩形配列とも呼ばれます。
|  (§.多次元配列 (矩形配列))
|
| 一方、ジャグ配列は配列を格納することができる配列(配列の配列)であり、その事から
| 多段配列とも呼ばれます。 ジャグ配列は、常に矩形である多次元配列とは異なり構造が
| ギザギザ(jagged)になることが、その名前の由来となっています。 (§.ジャグ配列 (多段配列))
|
| ジャグ配列は多次元配列とは異なり、異なる要素数の配列を格納することができます。 例えば、
| 2次元配列が持ちうる要素数は1次元目の長さがn、2次元目の長さがm個とすると計n×m個となり、
| 常に次元ごとの長さの積が全要素数となります。 一方、2段のジャグ配列ではa個の配列+b個の
| 配列+c個の配列…とジャグ配列内に格納されている配列の要素数の和となります。

# PCが不調となり、急遽バックアップ作業に追われてしまいました。
# まあ、全体がゴミなので、ゴミをバックアップしてどうするという気は正直しましたけどねえ。

(γ) 2020/09/18(金) 07:27


コメント返信:

[ 一覧(最新更新順) ]


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