エクセルVBA100本ノック。9本目:フィルターコピー
この記事から得るもの
Collectionオブジェクトの特徴。
AutoFilterの使い方。
Worksheetが存在するかチェックする処理。
Set 変数 = Worksheets(””)のスマートな書き方。
1 今回のお題
「成績表」シートに5教科の成績とG列に合否判定があります。
「合格者」シートを新規作成し、合格者の氏名だけをA列に列挙してください。
※点数は非公開なので「合格者」シートには間違っても出力しないでください。
※何度でも実行できるようにしてください。
2 今回のお題の意図
何度でも実行できるようにしてください。ということは、Sheetが残ったままだと新規Sheetを作成処理を書いている場合、すでに同じSheetがエラーとなって何度も実行することができません。そこに留意することと理解しました。
3 回答
私の最初の回答
Sub ノック9本目_1() Dim Ws As Worksheet: Set Ws = Worksheets("成績表") Dim SuccessfulCandidate As Collection: Set SuccessfulCandidate = New Collection '合格者をコレクションに入れる For SeachSuccessfulCandidate = 2 To Ws.Cells(Rows.Count, 1).End(xlUp).Row If Ws.Cells(SeachSuccessfulCandidate, 7) = "合格" Then SuccessfulCandidate.Add Ws.Cells(SeachSuccessfulCandidate, 1).Value End If Next '合格者Sheetが存在すれば削除する。 For Each SeachWs In Worksheets SheetName = SeachWs.Name If SheetName = "合格者" Then Application.DisplayAlerts = False SeachWs.Delete Application.DisplayAlerts = True Exit For End If Next '合格者Sheetを作る Worksheets.Add.Name = "合格者" Dim Ws2 As Worksheet: Set Ws2 = Worksheets("合格者") '合格者を書込 i = 0 For Each WriteSuccessfulCandidate In SuccessfulCandidate i = i + 1 Ws2.Range("A" & i) = SuccessfulCandidate.Item(i) Next End Sub
処理の流れはコメントの通りです。
1 合格者をコレクションに入れる
2 合格者Sheetが存在すれば削除する。
3 合格者Sheetを作る
4 合格者を書込
この流れでプロシージャを作成すれば、何度でも実行できるという要件に沿っていますね。
しかし、お題「フィルターコピー」とありますが、フィルターコピーやってねぇ~(;^ω^)。ということに気づきました。
また、コレクションに合格者を加えているので、同姓同名がいた場合対応できません。なぜなら、コレクションには重複したデータを入れることができないからです。
なので、フィルターコピーを使って上手に記述されている方のコードを見てみましょう。
吉田拳先生の回答
Sub 吉田拳先生の回答() Application.DisplayAlerts = False Dim i As Long, ws As Worksheet For i = Sheets.Count To 1 Step -1 If Sheets(i).Name = "合格者" Then: Sheets(i).Delete Next Set ws = Sheets.Add: ws.Name = "合格者" With Sheets("成績表") .Range("A1").AutoFilter field:=7, Criteria1:="合格" .Columns(1).Copy ws.Range("A1") .Range("A1").AutoFilter 'フィルタの解除 End With End Sub
オートフィルタをVBAで書いたことが無い私でも、こんな簡単に書けるのか~!と、わかりやすさに驚きです。
合格者Sheetが存在するかどうかの処理も、動きに無駄がないというかスマートな書き方ですね。
4 Worksheet追加時のスマートな書き方
1 Worksheetを加える。
2 Sheetに名前をつける。
3 WorksheetObuject変数に格納する(Set)。
この書き方で一番スマートなのはどれかなのか。
私の書き方
Worksheets.Add.Name = "合格者" Dim Ws2 As Worksheet: Set Ws2 = Worksheets("合格者")
吉田拳先生の書き方
Set ws = Sheets.Add: ws.Name = "合格者"
神髄先生の書き方
Set wsOut = Worksheets.Add(After:=wsIn) wsOut.Name = "合格者"
やはり、1行で書いているスマートさから、吉田拳先生に1票ですね。
神髄先生のも”:”で1行にしてやれば吉田先生と同じですね。
では、このへんで(^^)/~~~