質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.46%
VBA

VBAはオブジェクト指向プログラミング言語のひとつで、マクロを作成によりExcelなどのOffice業務を自動化することができます。

Q&A

解決済

4回答

1625閲覧

追加されていく名簿を、部ごとに分類し別シートに表示するマクロの実装について

20200713

総合スコア16

VBA

VBAはオブジェクト指向プログラミング言語のひとつで、マクロを作成によりExcelなどのOffice業務を自動化することができます。

0グッド

0クリップ

投稿2020/12/31 12:37

編集2021/01/01 10:59

前提・実現したいこと

excelで追加されていく名簿を別シートで部ごとに分類して表示したいです。

【sheet1】
営業部,山田
経理部,田中
営業部,鈴木
↓イベント発生(ボタンクリック等)
【sheet2】
営業部,経理部,財務部
山田,田中
鈴木

sheet1に人を追加する度、sheet2で列ごと(部ごと)に分類して表示したいです。
部の名前や数は既に決まっていることを前提としています。

試したこと・発生している問題・エラーメッセージ

2次元配列の各行の各部署のメンバー名を格納できたのですが、
新たな人員を追加する際いれる配列の場所を決める作業が
無駄が多いように感じています。

各行それぞれ別で列の数を決めるようなジャグ配列などを使うことで、
無駄を省くことができれば嬉しく思っております。
方法にこだわりはございませんので、効率の良い方法について
なにかアドバイスいただけましたら幸いです。

vba

1Sub click() 2 3'部のリスト 4 Dim n_category As Integer 5 n_category = 3 6 Dim list_category() 7 ReDim list_category(n_category, 2) 8 list_category(0, 0) = "営業部" 9 list_category(1, 0) = "経理部" 10 list_category(2, 0) = "財務部" 11 Dim i 12 For i = 0 To n_category 13 list_category(i, 1) = 0 14 Next 15 16 '名前分類の配列(list_category(0)営業部の人を0行に格納) 17 Dim strArray() 18 '3行1列の配列を用意 19 ReDim Preserve strArray(n_category, 0) 20 For i = 0 To ActiveSheet.Cells(Rows.Count, 1).End(xlUp).Row 'sheet1 rows 21 Dim j 'type of category 22 For j = 0 To n_category - 1 23 If (Cells(i + 1, 1) = list_category(j, 0)) Then 24 list_category(j, 1) = list_category(j, 1) + 1 25 Dim size, k 26 size = 0 27 For k = 0 To n_category - 1 28 If (list_category(k, 1) > size) Then 29 size = list_category(k, 1) 'decide Column size 30 Cells(i + 1, 3) = size 31 End If 32 Next 33 ReDim Preserve strArray(n_category, size) 34 strArray(j, list_category(j, 1) - 1) = Cells(i + 1, 2) 35 36 Exit For 37 End If 38 Next 39 Next 40 41 For i = 0 To n_category - 1 42 Worksheets("Sheet2").Cells(1, i + 1) = list_category(i, 0) 43 Next 44 45 For i = 0 To n_category - 1 46 For j = 0 To size - 1 47 Worksheets("Sheet2").Cells(j + 2, i + 1) = strArray(i, j) 48 Next 49 Next 50End Sub

名簿の部署名によって分類していく際に、
入れるべき配列の場所(任意の部署行の最終列の次)を特定するのが楽なのかと思い
コメントにてお教えいただいたジャグ配列が適当なのかと考えておりました。

具体的には既に配列が以下のような時、
営業部(0行目) 山田,鈴木
経理部(1行目) 田中
財務部(2行目)
「経理部 佐藤」を追加する際、配列の箇所指定はどのようにするのが好ましいでしょうか。

ちなみにこの度はsheet2に部署ごとの並びとして貼り付け、
事前にその範囲を名前の定義しておいたリストを別の場所でドロップダウンリストとして用いる予定です。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

meg_

2020/12/31 14:58

コードを掲載しましょう。
20200713

2021/01/01 03:01

コメントありがとうございます。コード掲載いたしました。
vann_2921

2021/01/01 06:07

確認なんですが、どうして各部署について長さの異なる配列を保持するようにしたいのでしょうか? 長さの異なる配列の配列はジャグ配列と言って人が扱うには直感的に分かりやすく余分な要素を持たないのでメモリも節約できますがエクセルVBAでは2次元配列特有のメリットがあります。 2次元配列を val(1 To 3, 1 To 2) のように1から始まるインデックスで確保することでRange("A1:B3").Value = val とすることで一回ですべてのセルに代入できます。 質問文からはSheet1からSheet2へ転記する処理と思いますのでジャグ配列より2次元配列のままの方がメリットがありそうな気がします。 もう少し、2次元配列でどんなことに困っているのか説明してもらえるとより良い回答ができるかと思います。
20200713

2021/01/01 08:44

コメントありがとうございます。現状について追記いたしました!
guest

回答4

0

DictionaryとArrayListを使った例です。
Dictionaryのキーに部署名をセットします。キーに対応する値はArralistになります。
Dictionaryについては
https://tonari-it.com/excel-vba-dictionary-object/
https://www.sejuku.net/blog/29736
ArrayListについては
https://www.yuu-progra.com/2019/11/30/vba-arraylist/
https://vbabeginner.net/use-net-framework-arraylist/
あたりを参考にしてください。

部署数は予め決まっている必要はありません。
各部署の氏名も同様です。

VBA

1Public Sub 部署毎に並び替え() 2 Dim wrow As Long 3 Dim wcol As Long 4 Dim maxrow As Long 5 Dim dicT As Object 'Dictionary 6 Dim ArrList As Object 'ArrayList 7 Dim key As Variant 8 Dim name As String 9 Dim i As Long 10 Dim sh1 As Worksheet 11 Dim sh2 As Worksheet 12 Set sh1 = Worksheets("Sheet1") 13 Set sh2 = Worksheets("Sheet2") 14 maxrow = sh1.Cells(rows.Count, 1).End(xlUp).row 'sheet1 最終行を求める 15 Set dicT = CreateObject("Scripting.Dictionary") ' 連想配列の定義 16 'Sheet1を1から最終行まで処理 17 For wrow = 1 To maxrow 18 key = sh1.Cells(wrow, "A").value '部署名 19 If dicT.exists(key) = False Then 20 '部署名未登録時、部署をDictionaryに登録 21 Set ArrList = CreateObject("System.Collections.ArrayList") '.NET Frameworkへの参照 22 dicT.Add key, ArrList 23 End If 24 name = sh1.Cells(wrow, "B").value '氏名 25 dicT(key).Add name '氏名を当該部署に追加 26 Next 27 sh2.Cells.Clear 28 wcol = 1 29 'Dictionaryの全てのキー(部署)を処理 30 For Each key In dicT 31 sh2.Cells(1, wcol).value = key 32 'ArrayList中の氏名を全て出力 33 For i = 0 To dicT(key).Count - 1 34 sh2.Cells(2 + i, wcol).value = dicT(key)(i) 35 Next 36 wcol = wcol + 1 37 Next 38 MsgBox ("完了") 39End Sub

実行結果
イメージ説明

投稿2021/01/02 08:23

tatsu99

総合スコア5470

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

20200713

2021/01/03 02:54

ご回答いただきありがとうございます。 こちら理想的に思い自分の環境でも実装してみたのですが、 以下のエラーが出てしまいました。 記載いただいたものそのままなのでエラーの理由が不明なのですが、 何かご意見いただけましたら助かります…! 実行時エラー'429': ActiveX コンポーネントはオブジェクトを作成できません。 コード該当箇所 Set dicT = CreateObject("Scripting.Dictionary") ' 連想配列の定義
tatsu99

2021/01/03 03:06

もしかして、環境はmacでしょうか。macではDictionaryはサポートしていません。 windowsでないと使用できません。
20200713

2021/01/03 03:20

そうなのですね…!当方、環境はmacです… Dictionary便利そうなので大変残念ですが、利用を断念いたします…!
guest

0

list_category(0, 0) = "営業部"
list_category(1, 0) = "経理部"
list_category(2, 0) = "財務部"
部署が追加になった場合、コード書き換えするのですか?
私の場合、これしか思い浮かびませんでした。
サンプルコード記載します

VBA

1Sub Test() 2Dim 部署 As String 3Dim 担当 As String 4Dim i As Long 5Dim Ro As Long '最終行 6Dim Col As Long '最終列 7 8 Sheets("入力").Select 9 部署 = Cells(2, 3).Value 10 担当 = Cells(3, 3).Value 11 Sheets("社員MS").Select 12 Col = Cells(1, Columns.Count).End(xlToLeft).Column 13 For i = 1 To Col 14 Ro = Cells(Rows.Count, i).End(xlUp).Row + 1 15 If 部署 = Cells(1, i) Then 16 Cells(Ro, i) = 担当 17 Exit For 18 End If 19 Next i 20 Sheets("入力").Select 21End Sub 22

イメージ説明

投稿2021/01/01 14:35

syousuke.33

総合スコア312

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

sheet1に項目名(A1に「部署名」、B1に「氏名」)を入れておき
オートフィルターを使えばいいと思います。
部署ごとの氏名が必要ならこの後sheet2からとれます。

vba

1Sub click() 2 3 '部のリスト 4 Dim n_category As Integer 5 n_category = 3 6 Dim list_category() As String 7 ReDim list_category(n_category) 8 list_category(1) = "営業部" 9 list_category(2) = "経理部" 10 list_category(3) = "財務部" 11 12 Dim ws1 As Worksheet: Set ws1 = Worksheets("sheet1") 13 Dim ws2 As Worksheet: Set ws2 = Worksheets("sheet2") 14 15 ws2.Cells.Clear 16 17 Dim i As Long 18 For i = 1 To UBound(list_category) 19 With ws1 20 .Range("a1").CurrentRegion.AutoFilter field:=1, Criteria1:=list_category(i) 21 Dim rng As Range 22 Set rng = .Cells(Rows.Count, 2).End(xlUp) 23 If rng.Row <> 1 Then 24 .Range(.Range("b2"), rng).SpecialCells(xlCellTypeVisible).Copy 25 End If 26 End With 27 With ws2 28 .Cells(1, i) = list_category(i) 29 If rng.Row <> 1 Then 30 .Cells(Rows.Count, i).End(xlUp).Offset(1).PasteSpecial 31 End If 32 End With 33 Next i 34 35 ws1.AutoFilterMode = False 36End Sub

投稿2021/01/01 08:12

radames1000

総合スコア1923

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

ベストアンサー

要素ごとに長さの異なる配列(ジャグ配列)を作成するときはVariant型の配列を用意し、その要素ごとに別の配列を用意します。

vba

1Dim v(2) as Variant 'Variant型の配列 2Dim elm1(3) as Variant '要素1 3Dim elm2(1) as Variant '要素2 4Dim elm3(2) as Variant '要素3 5v(0) = elem1 6v(1) = elem2 7v(2) = elem3 8v(0)(1) ' 1番目の要素の2個目にアクセス v(0, 1)ではない。

みたいな感じです。

投稿2021/01/01 06:15

vann_2921

総合スコア190

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

20200713

2021/01/03 04:14

この度は探していたようなジャグ配列についてお教えいただいたこちらをベストアンサーとさせていただきます。最終的には二次元配列で実装いたしましたが、ご相談きいていただきありがとうございました。 他の方々も知らなかった方法をお教えいただき大変勉強になりました。必要な局面でつけるよう勉強いたします!
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.46%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問