[ 初めての方へ | 一覧(最新更新順) | 全文検索 | 過去ログ ]
『Excel VBAについて(親子関係から組織図を作る)質問です。』(neko)
Excel VBAについて(親子関係から組織図を作る)質問です。
親子関係にある表から組織図を作成したいと思っています。
A列からD列までのデータをもとにF列以降に出力します。
1 A、B列の所属と同じ行にある親にあたるC、D列をみる
2 C列の値から、A列の値を参照し、該当があれば、その同じ行の親所属を参照する。該当があるまで繰り返す。
A列 B列 C列 D列 所属コード 所属名 親所属コード 親所属名 1 社長 2 企画部 1 社長 3 総務部 2 企画部 4 営業 2 企画部 5 営業1 4 営業
完成形(同じシートのE列以降に出力) 1 社長 1 社長 2 企画部 1 社長 2 企画部 3 総務部 1 社長 2 企画部 4 営業 1 社長 2 企画部 4 営業 5 営業1
辞書機能などを使うと出来るかな?と思い、辞書にアイテムを入れるところまで作成したのですが、1、2の動きができません。
もしくは、辞書を使わないでもっと良い方法があるかもと思っているのですが、分かる方いらっしゃいましたら、ご教示お願いします<m(__)m>
※↓は途中まで作成して止まっている状態です。
Sub 所属名作成()
Dim i As Long, j As Long, 範囲 As Variant, i2 As Long
Dim 元 As Worksheet
Dim unit_code As String, unit_name As String
Dim p_unit_code As String, p_unit_name As String
Dim myDic As Object
Set myDic = CreateObject("Scripting.Dictionary")
Dim key As String
Dim item() As Variant
With Worksheets("sheet1")
For i = 2 To .Cells(.Rows.Count, 1).End(xlUp).Row
myDic(.Cells(i, 1).Value & .Cells(i, 2).Value) = Array(.Cells(i, 1).Value, _
.Cells(i, 2).Value)
Next i
End With
Set 元 = Sheets("Sheet1")
範囲 = 元.UsedRange.Value
For i2 = 2 To UBound(範囲)
unit_code = 元.Cells(i2, 1)
unit_name = 元.Cells(i2, 2)
p_unit_code = 元.Cells(i2, 3)
p_unit_name = 元.Cells(i2, 4)
key = unit_code & unit_name
If myDic.Exists(key) Then
item = myDic(key)
End If
If item(2) = "" Then
Cells(i2, 7) = item(0)
Cells(i2, 8) = item(1)
Exit For
Else
End If
Next i2
End Sub
< 使用 Excel:Microsoft365、使用 OS:Windows11 >
1回のループではだめかもしれませんが、データ次第。 Sub test() Dim dic As Object Dim r As Range Dim v Dim k As Long Dim s1 As String, s2 As String
Set dic = CreateObject("scripting.dictionary") Set r = Cells(1).CurrentRegion.Resize(, 5) v = r.Value
For k = 2 To UBound(v) s1 = v(k, 1) & " " & v(k, 2) s2 = v(k, 3) & " " & v(k, 4) dic(s1) = Trim(dic(s2) & " " & s1) v(k, 5) = dic(s1) Next r.Value = v
Set r = r.Columns(5) r.TextToColumns Destination:=r, DataType:=xlDelimited, _ Tab:=False, Semicolon:=False, Comma:=False, Space:=True, _ Other:=False
End Sub (マナ) 2025/01/08(水) 20:57:09
「データ次第」と書いたのは
親コード<子コード の関係であることが前提。 本番データがそうでないなら、期待通りの結果になりません。
その場合は下記で。(地道に処理を繰り返す以外のアイデアは思いつきませんでした)
Sub test2() Dim dic As Object Dim r As Range Dim v, v2() As String Dim k As Long Dim s1 As String, s2 As String, s3 As String
Set dic = CreateObject("scripting.dictionary") ActiveSheet.UsedRange.Offset(, 4).ClearContents Set r = Cells(1).CurrentRegion v = r.Value ReDim v2(1 To r.Rows.Count, 1 To 1)
For k = 2 To UBound(v) s1 = v(k, 1) & " " & v(k, 2) s2 = v(k, 3) & " " & v(k, 4) Set dic(s1) = CreateObject("system.collections.arraylist") If s2 <> " " Then dic(s1).Add s2 dic(s1).Add s1 Next
For k = 2 To UBound(v) s1 = v(k, 1) & " " & v(k, 2) s2 = v(k, 3) & " " & v(k, 4) If s2 <> " " Then Do s3 = dic(s1)(0) If Not dic.exists(s3) Then Exit Do If dic(s3).Count = 1 Then Exit Do dic(s1).removeat 0 dic(s1).insertrange 0, dic(s3) Loop
If dic(s1).Count - 1 > dic(s2).Count Then Set dic(s2) = dic(s1).getrange(0, dic(s1).Count - 1) End If End If v2(k, 1) = Join(dic(s1).toarray, " ") Next
Set r = r.Columns(5) r.Value = v2
r.TextToColumns Destination:=r, DataType:=xlDelimited, _ Tab:=False, Semicolon:=False, Comma:=False, Space:=True, _ Other:=False
End Sub (マナ) 2025/01/11(土) 20:10:24
横から失礼します。つかぬことをお聞きします。 結果として得られるものは、組織図の材料にはなるものの、 一般的な組織図(という図そのもの)ではないですよね。 その後、どのように図を作成されるのか、参考までに教えていただけますか?
(xyz) 2025/01/17(金) 08:33:59
既に解決済みですけど、私も作っていたので参考出品しておきます。
Rem 親子関係からなるtree構造の全パスを取り出す Dim dic As Object '親組織 => 子組織たち を保持するdictionary Sub main() Dim root As Object Dim lastRow&, k& Dim s1$, s2$ Dim r As Variant Dim rng As Range '書き込み先のセル範囲 Dim p& '書き込み用配列の行index
lastRow = Cells(Rows.Count, "A").End(xlUp).Row
'(1)親子関係を辞書に保持 Set dic = CreateObject("Scripting.Dictionary") ' dic key: 親組織 , item : その子組織をカンマで連結した文字列 For k = 2 To lastRow s1 = Cells(k, "A") s2 = Cells(k, "B") If dic.Exists(s1) Then dic(s1) = dic(s1) & "," & s2 Else dic(s1) = s2 End If Next
'(2)Root(親を持たないnode)を検索 Set root = CreateObject("Scripting.Dictionary") For k = 2 To lastRow root(Cells(k, "A").Value) = Empty '親たちをroot候補として登録 Next For k = 2 To lastRow s2 = Cells(k, "B").Value If root.Exists(s2) Then root.Remove s2 'それが何かの子になっていれば、それはrootから外す Next
'(3)rootから始まるtreeを走査して、 ' rootから始まる親子ペアの連結文字列を取得(深さ優先探索を使う再帰処理) ReDim v(1 To 1) As String For Each r In root Call dfs(CStr(r), r, p, v) Next
'(4)結果をシートに書き込み Set rng = Range("E2").Resize(p, 1) rng.Value = Application.Transpose(v) rng.TextToColumns Destination:=rng, DataType:=xlDelimited, _ Tab:=False, Semicolon:=False, Comma:=True, Space:=False, Other:=False End Sub
Function dfs(ss As String, parent As Variant, p As Long, v() As String) 'depth-first search Dim child As Variant Dim concatStr As String For Each child In Split(dic(parent), ",") concatStr = ss & "," & child Call setData(p, v, concatStr) 'カンマによる連結文字列を結果配列に書き込み Call dfs(concatStr, child, p, v) '子に対して再帰処理を行う Next End Function
'結果書き込みのヘルパー関数 Function setData(p As Long, v() As String, s As String) p = p + 1 ReDim Preserve v(1 To p) v(p) = s End Function
ああ、入力データは↓のようなものを想定していました。(質問のものと若干違います) A列 B列 1 社長 企画部 2 企画部 総務部 3 企画部 営業 4 営業 営業1 5 社長 企画2部 6 企画2部 総務2部 7 企画2部 営業2 8 営業2 営業3
(xyz) 2025/01/23(木) 10:02:44
こんばんは! ちょっろと私風に書いてみました。 相変わらずの私風です。。。(^^; 考え方はディクショナリーで親子関係を関連付けておいて 「私の親は誰」で親がいなくなるまで繰り返します。 ちょっと検証不足なので後は例によってアレンジしていただけますと幸甚です。 では、、、おやすみなさいzzzzzzzzzzzzzzzzzzzzzzzz
Option Explicit Sub 親子関係() Dim MyDic As Object Dim v As Variant Dim i As Long Dim j As Long Dim k As Long Dim kk As Long Dim x As Variant Set MyDic = CreateObject("Scripting.Dictionary") v = Sheets("Sheet1").Range("A1").CurrentRegion.Resize(, 4).Value For i = LBound(v, 1) + 1 To UBound(v, 1) MyDic(v(i, 1) & v(i, 2)) = v(i, 3) & v(i, 4) Next x = MyDic.Keys ReDim z(0) ReDim w(1 To UBound(x) + 1, 1 To 1) For i = LBound(x) To UBound(x) 私の親は誰 MyDic, x(i), z, False k = k + 1 kk = 0 For j = UBound(z) To LBound(z) Step -1 If z(j) <> "" Then kk = kk + 1 w(k, kk) = z(j) End If Next ReDim Preserve w(LBound(w, 1) To UBound(w, 1), 1 To UBound(w, 2) + 1) Next With Sheets("Sheet2") .Cells.Clear .Range("a1").Resize(UBound(w, 1), UBound(w, 2)).Value = w End With Erase v, x, z, w End Sub Sub 私の親は誰(ByVal MyD As Object, ByRef MyKey As Variant, ByRef z As Variant, ByRef MyFlg As Boolean) Static q As Variant If MyFlg = False Then MyFlg = True ReDim q(0) q(0) = MyKey End If If MyFlg Then ReDim Preserve q(UBound(q) + 1) q(UBound(q)) = MyD(MyKey) z = q If MyD(MyKey) = "" Then Exit Sub 私の親は誰 MyD, MyD(MyKey), z, True End If End Sub
|[A] |[B] |[C] |[D] [1]|所属コード|所属名|親所属コード|親所属名 [2]| 1|社長 | | [3]| 2|企画部| 1|社長 [4]| 3|総務部| 2|企画部 [5]| 4|営業 | 2|企画部 [6]| 5|営業1 | 4|営業
|[A] |[B] |[C] |[D] [1]|1社長| | | [2]|1社長|2企画部| | [3]|1社長|2企画部|3総務部| [4]|1社長|2企画部|4営業 | [5]|1社長|2企画部|4営業 |5営業1 (SoulMan) 2025/01/23(木) 19:43:20
こういうの考えるのって面白いですよね
'---------- 標準モジュール -------------- Sub sample() Dim AllSection As New Collection Dim section As clsSection, parent As clsSection Dim aRow As Range '全セクションを生成 For Each aRow In Range("A2", Cells(Rows.Count, "A").End(xlUp)).Rows Set section = New clsSection With section .ID = aRow.Cells(1, 1) .Name = aRow.Cells(1, 2) .parentID = aRow.Cells(1, 3) End With AllSection.Add section, section.ID Next '子供を登録 For Each section In AllSection If Not IsEmpty(section.parentID) Then AllSection(section.parentID).children.Add section End If Next '書き出し For Each section In AllSection If IsEmpty(section.parentID) Then section.PrintChildren "F" End If Next Columns("F").TextToColumns Destination:=Range("F1"), DataType:=xlDelimited, Tab:=True End Sub '---------- clsSection モジュール -------------- Public ID As String, Name As String, parentID As Variant Public children As New Collection Function PrintChildren(col As Variant, Optional ByVal pre As String = "") Dim child As clsSection pre = pre & IIf(pre = "", "", vbTab) & Me.ID & vbTab & Me.Name Cells(Rows.Count, col).End(xlUp).Offset(1).Value = pre For Each child In children child.PrintChildren col, pre Next End Function (´・ω・`) 2025/01/24(金) 10:43:23
こんにちは! いいねぇ、、いいねぇ、、いいですねぇ、、学校らしくなってきましたねぇ(^^; わちきのロジックはCollectionなんかに置き換えてもそのままいけると思いますが、 それじゃ面白くないでしょうから、ここは敢えてオブジェクトを使わずに且つなるべく 現在の「親子関係」のロジックを変えないでもう一つアップしてみます。
題して「親子関係ディクショナリーなんていらねぇ」ネーミングが例によって長い(^^;です。。。 お許しをm(__)m 相変わらずのわちき流でございます。 では、、では、、
Option Explicit Sub 親子関係ディクショナリーなんていらねぇ() Dim v As Variant Dim x As Variant Dim i As Long Dim j As Long Dim k As Long Dim kk As Long ReDim d(0) ReDim g(0) v = Sheets("Sheet1").Range("A1").CurrentRegion.Resize(, 4).Value For i = LBound(v, 1) + 1 To UBound(v, 1) x = Application.Match(v(i, 1) & v(i, 2), d, 0) If IsError(x) Then ReDim Preserve d(UBound(d) + 1) d(UBound(d)) = v(i, 1) & v(i, 2) ReDim Preserve g(UBound(g) + 1) g(UBound(g)) = v(i, 3) & v(i, 4) End If Next ReDim z(0) ReDim w(1 To UBound(d), 1 To 1) For i = LBound(d) + 1 To UBound(d) 私の親は誰 d, g, d(i), z, False k = k + 1 kk = 0 For j = UBound(z) To LBound(z) Step -1 If z(j) <> "" Then kk = kk + 1 w(k, kk) = z(j) End If Next ReDim Preserve w(LBound(w, 1) To UBound(w, 1), 1 To UBound(w, 2) + 1) Next With Sheets("Sheet2") .Cells.Clear .Range("a1").Resize(UBound(w, 1), UBound(w, 2)).Value = w End With Erase v, d, g, z, w End Sub Sub 私の親は誰(ByVal d As Variant, ByVal g As Variant, ByRef MyKey As Variant, ByRef z As Variant, ByRef MyFlg As Boolean) Dim x As Variant Dim y As Variant Static q As Variant If MyFlg = False Then MyFlg = True ReDim q(0) q(0) = MyKey End If If MyFlg Then x = Application.Match(MyKey, d, 0) If Not IsError(x) Then y = g(x - 1) End If ReDim Preserve q(UBound(q) + 1) q(UBound(q)) = y z = q If y = "" Then Exit Sub 私の親は誰 d, g, y, z, True End If End Sub (SoulMan) 2025/01/24(金) 17:25:13
[ 一覧(最新更新順) ]
YukiWiki 1.6.7 Copyright (C) 2000,2001 by Hiroshi Yuki.
Modified by kazu.