Dictionaryによる属性リストの横展開(可変列方式)
※ 保有属性を右方向に連番列として展開する形式


Option Explicit
Sub CreateEmployeeQualificationList()
Dim ws As Worksheet
Set ws = ThisWorkbook.Worksheets("Sheet5")
Dim dictEmp As Object '社員ごとの辞書
Dim dictLic As Object '資格辞書
Set dictEmp = CreateObject("Scripting.Dictionary")
dictEmp.CompareMode = vbTextCompare '文字列比較
Dim lastRow As Long
Dim dataArray As Variant
Dim i As Long
With ws
lastRow = .Cells(.Rows.Count, "A").End(xlUp).row
' 出力列クリア&見出し
.Range("F:M").ClearContents
.Range("F1").Value = "社員番号"
.Range("G1").Value = "名前"
.Range("H1").Value = "部署"
If lastRow < 2 Then Exit Sub
' 入力配列化
dataArray = .Range("A2:D" & lastRow).Value
End With
Dim empNo As String, empName As String, empDept As String, lic As String
' --- 集計処理 ---
For i = 1 To UBound(dataArray, 1)
empNo = Trim(dataArray(i, 1))
empName = Trim(dataArray(i, 2))
empDept = Trim(dataArray(i, 3))
lic = Trim(dataArray(i, 4))
If Len(empNo) > 0 Then
' 初回の社員登録
If Not dictEmp.Exists(empNo) Then
Set dictLic = CreateObject("Scripting.Dictionary")
dictLic.CompareMode = vbTextCompare
dictEmp.Add empNo, Array(empName, empDept, dictLic)
End If
' 中身の参照
empName = dictEmp(empNo)(0)
empDept = dictEmp(empNo)(1)
Set dictLic = dictEmp(empNo)(2)
' 資格(重複排除)
If Len(lic) > 0 Then
If Not dictLic.Exists(lic) Then
dictLic.Add lic, True
End If
End If
End If
Next i
' --- 社員番号(文字列)でソート ---
Dim keys As Variant, sorted As Variant
keys = dictEmp.keys
sorted = SortStringArray(keys) '後述の関数でソート
' --- 出力作成 ---
Dim result() As Variant
Dim r As Long: r = 1
Dim col As Long, maxLicCount As Long, licKey As Variant
' 一旦最大列をざっくり確保
ReDim result(1 To dictEmp.Count, 1 To 100)
Dim emp As Variant, empInfo As Variant
For Each emp In sorted
empInfo = dictEmp(emp)
Set dictLic = empInfo(2)
result(r, 1) = emp
result(r, 2) = empInfo(0)
result(r, 3) = empInfo(1)
col = 4
For Each licKey In dictLic.keys
result(r, col) = licKey
col = col + 1
Next licKey
' 最大列数を記録
If col - 4 > maxLicCount Then maxLicCount = col - 4
r = r + 1
Next emp
' 動的サイズに縮めて書き戻し
ws.Range("F2").Resize(dictEmp.Count, 3 + maxLicCount).Value = result
' --- 資格列の見出し作成 ---
Dim iCol As Long
For iCol = 1 To maxLicCount
ws.Cells(1, 9 + iCol - 1).Value = "資格名_" & iCol
Next iCol
MsgBox "社員資格一覧が完成しました!", vbInformation
End Sub
' ----▼簡易文字列ソート関数(昇順)---------
Private Function SortStringArray(arr As Variant) As Variant
Dim i As Long, j As Long
Dim temp As String
For i = LBound(arr) To UBound(arr) - 1
For j = i + 1 To UBound(arr)
If arr(i) > arr(j) Then
temp = arr(i)
arr(i) = arr(j)
arr(j) = temp
End If
Next j
Next i
SortStringArray = arr
End FunctionDictionaryによる属性フラグの横展開(マトリックス化方式)
※ 各属性の有無を 〇/空欄(Boolean)で表す形式


Sub CreateEmployeeLicenseMatrix()
Dim wsData As Worksheet
Dim wsLic As Worksheet
Set wsData = ThisWorkbook.Worksheets("Sheet6") '元データ
Set wsLic = ThisWorkbook.Worksheets("資格名一覧") '資格マスタ
Dim dictEmp As Object, dictLic As Object
Set dictEmp = CreateObject("Scripting.Dictionary")
dictEmp.CompareMode = vbTextCompare
Dim lastRow As Long, maxLic As Long
Dim dataArray As Variant, licListArray As Variant
Dim i As Long
' ================================
' ■資格マスタ取得
' ================================
With wsLic
maxLic = .Cells(.Rows.Count, "A").End(xlUp).row
licListArray = .Range("A1:A" & maxLic).Value '縦方向配列(1始まり)
End With
' ================================
' ■元データ取得
' ================================
With wsData
lastRow = .Cells(.Rows.Count, "A").End(xlUp).row
' F以降クリア
.Range("F:Z").ClearContents
If lastRow < 2 Then Exit Sub
dataArray = .Range("A2:D" & lastRow).Value
End With
Dim empNo As String, empName As String, empDept As String, lic As String
' ================================
' ■社員情報 × 資格Dictionary作成
' ================================
For i = 1 To UBound(dataArray, 1)
empNo = Trim(dataArray(i, 1)) '文字列3桁社員番号
empName = Trim(dataArray(i, 2))
empDept = Trim(dataArray(i, 3))
lic = Trim(dataArray(i, 4))
If Len(empNo) > 0 Then
' 新規社員登録
If Not dictEmp.Exists(empNo) Then
Set dictLic = CreateObject("Scripting.Dictionary")
dictLic.CompareMode = vbTextCompare
dictEmp.Add empNo, Array(empName, empDept, dictLic)
End If
Set dictLic = dictEmp(empNo)(2)
' 資格重複排除
If Len(lic) > 0 Then
If Not dictLic.Exists(lic) Then
dictLic.Add lic, True
End If
End If
End If
Next i
' ================================
' ■社員番号ソート(文字列昇順)
' ================================
Dim arrKeys As Variant
arrKeys = dictEmp.keys
arrKeys = SortStringArray(arrKeys) '※後述
' ================================
' ■結果出力用配列作成
' ================================
Dim result() As Variant
Dim r As Long: r = 1
Dim c As Long, e As Variant
ReDim result(1 To dictEmp.Count, 1 To maxLic + 3)
For Each e In arrKeys
result(r, 1) = e
result(r, 2) = dictEmp(e)(0)
result(r, 3) = dictEmp(e)(1)
Set dictLic = dictEmp(e)(2)
For c = 1 To maxLic
If dictLic.Exists(licListArray(c, 1)) Then
result(r, c + 3) = "○"
End If
Next c
r = r + 1
Next e
' ================================
' ■シート出力(見出し付き)
' ================================
Dim ws As Worksheet
Set ws = wsData '直接出力する位置
ws.Range("F1").Value = "社員番号"
ws.Range("G1").Value = "名前"
ws.Range("H1").Value = "部署"
For c = 1 To maxLic
ws.Cells(1, 8 + c).Value = licListArray(c, 1) 'I列?
Next c
ws.Range("F2").Resize(dictEmp.Count, maxLic + 3).Value = result
MsgBox "資格マトリクス表が完成しました!", vbInformation
End Sub
'---▼文字列配列昇順ソート関数▼---
Private Function SortStringArray(arr As Variant) As Variant
Dim i As Long, j As Long
Dim tmp As String
For i = LBound(arr) To UBound(arr) - 1
For j = i + 1 To UBound(arr)
If arr(i) > arr(j) Then
tmp = arr(i): arr(i) = arr(j): arr(j) = tmp
End If
Next j
Next i
SortStringArray = arr
End Function
Dictionaryによる属性フラグの横展開(マトリックス化方式)2
※ データの更新「〇」のみを出力


Option Explicit
Sub UpdateEmployeeLicenseMatrix()
Dim wsData As Worksheet
Dim wsLic As Worksheet
Set wsData = ThisWorkbook.Worksheets("Sheet6")
Set wsLic = ThisWorkbook.Sheets("資格名一覧")
' ---------------------------
' ■資格マスタ取得(縦方向A列)
' ---------------------------
Dim maxLic As Long
Dim licList As Variant
maxLic = wsLic.Cells(wsLic.Rows.Count, "A").End(xlUp).row
licList = wsLic.Range("A1:A" & maxLic).Value
' ---------------------------
' ■元資格データ取得(A:D)
' ---------------------------
Dim lastRow As Long
lastRow = wsData.Cells(wsData.Rows.Count, "A").End(xlUp).row
If lastRow < 2 Then Exit Sub
Dim data As Variant
data = wsData.Range("A2:D" & lastRow).Value
' ---------------------------
' ■資格情報集計
' empNo → 資格Dictionary
' ---------------------------
Dim dictEmp As Object, dictLic As Object
Set dictEmp = CreateObject("Scripting.Dictionary")
dictEmp.CompareMode = vbTextCompare
Dim i As Long
Dim empNo As String, lic As String
For i = 1 To UBound(data, 1)
empNo = Trim(data(i, 1))
lic = Trim(data(i, 4))
If Len(empNo) > 0 And Len(lic) > 0 Then
If Not dictEmp.Exists(empNo) Then
Set dictLic = CreateObject("Scripting.Dictionary")
dictLic.CompareMode = vbTextCompare
dictEmp.Add empNo, dictLic
End If
Set dictLic = dictEmp(empNo)
If Not dictLic.Exists(lic) Then
dictLic.Add lic, True
End If
End If
Next i
' ---------------------------
' ■資格列クリア(I列以降)
' ---------------------------
wsData.Range("I2:ZZ" & wsData.Rows.Count).ClearContents
' ---------------------------
' ■資格ヘッダ設定(I1~)
' ---------------------------
Dim c As Long
For c = 1 To maxLic
wsData.Cells(1, 8 + c).Value = licList(c, 1) 'I列開始
Next c
' ---------------------------
' ■社員一覧(F2~)に対して○反映
' ---------------------------
Dim lastEmp As Long
lastEmp = wsData.Cells(wsData.Rows.Count, "F").End(xlUp).row
For i = 2 To lastEmp
empNo = Trim(wsData.Cells(i, "F").Value)
If Len(empNo) > 0 Then
If dictEmp.Exists(empNo) Then
Set dictLic = dictEmp(empNo)
For c = 1 To maxLic
If dictLic.Exists(licList(c, 1)) Then
wsData.Cells(i, 8 + c).Value = "○" '資格位置へ
End If
Next c
End If
End If
Next i
MsgBox "資格マトリクスを最新情報に更新しました!", vbInformation
End Sub

コメント