- ベストアンサー
For Eachを使った並び替えについて
- VBAXPで、5名を1組とし、班長を固定して4通りの組を作成する方法について質問です。
- Sub名簿()内のコードを繰り返し実行し、組2, 組3, 組4においても同様の作業を行いたいと思っています。
- また、同じ組合せや同じ班長の組が出ないようにする方法についても教えていただきたいです。
- みんなの回答 (3)
- 専門家の回答
質問者が選んだベストアンサー
こんにちは。 音沙汰がないので、サンプルのコードだけ提示します。 ステップ実行しながら処理を理解し、必要な処理を組み込んだり修正すれば目的の処理には、近づくと思います。 がんばってください。 【ステップ実行の仕方(釈迦に説法かもしれませんが……)】 Alt+F8でマクロ(返事がないので)を選択し、編集ボタンをクリックします。 VBEのコードウィンドウがアクティブになりますから、コードとワークシートが見えるように位置を変更します。 [F8]を押す度にと1行ずつ処理を実行していきます。 その処理が何を意味しているのか、どんな値を判定しているのか理解するのに役立ちます。 Sub 返事がないので() 'サンプルブックに8個のデータを作成し、 '班長が重複しない4組の、 '班長が固定された4つのグループを作成する Dim OldSheetsCount As Long '現在の新規ブックのシート数 Dim NewBook As Workbook '新規ブック Dim mySht As Worksheet '"Sheet1"ワークシート Dim NameListRange As Range '名前リスト範囲 Dim NameArea As Variant '各名前定義範囲 Dim Target As Range '名前定義したセル Dim LeaderRange As Range '班長セル Dim SortRange As Range '並べ替え範囲 Dim CopyRange As Range 'コピー範囲 Dim CountOfCopy 'コピー回数 '------------------------------------------------------------ '新規でサンプルブックを作成 With Application OldSheetsCount = .SheetsInNewWorkbook .SheetsInNewWorkbook = 1 .Calculation = xlCalculationManual End With Set NewBook = Workbooks.Add Application.SheetsInNewWorkbook = OldSheetsCount Set mySht = NewBook.Worksheets(1) With mySht .Range("E4,E6,K4,K6").Name = "Kumi1" .Range("E8,E10,K8,K10").Name = "Kumi2" .Range("E12,E14,K12,K14").Name = "Kumi3" .Range("E16,E18,K16,K18").Name = "Kumi4" Set NameListRange = .Range("A2:H2") With NameListRange Set LeaderRange = .Range("A1") Set SortRange = .Resize(2).Offset(-1) Set CopyRange = .Resize(, 4).Offset(, 1) .Font.Name = "MS ゴシック" .HorizontalAlignment = xlCenter .Offset(-1).Value = "=RAND()" End With For Each Target In NameListRange With Target .Value = Replace(Left(.Address, 3), "$", Mid(.Address, 2, 1)) .Interior.ColorIndex = .Column + 32 End With Next Target '------------------------------------------------------------ '各名前定義に対する処理 ' For Each NameArea In Array("Kumi1", "Kumi2", "Kumi3", "Kumi4") ' For Each Target In .Range(NameArea) ' Target.Resize(, 5).Offset(, -4).Clear ' Next Target ' Next NameArea For Each NameArea In Array("Kumi1", "Kumi2", "Kumi3", "Kumi4") Application.Calculate SortRange.Sort Key1:=SortRange.Range("A1"), _ Header:=xlNo, Orientation:=xlLeftToRight '------------------------------------------------------------ '班長の転記 'CopyDataCheckを呼び出し、班長範囲と各名前定義範囲の 'データが重複していないか調べ、 '重複していなければ班長を転記 '重複していたら、並べ替える Do If CopyDataCheck(CopyRange:=LeaderRange, _ CheckRange:=Union(.Range("Kumi1").Range("A1"), _ .Range("Kumi2").Range("A1"), _ .Range("Kumi3").Range("A1"), _ .Range("Kumi4").Range("A1")), _ CheckPosition:=0) = False Then LeaderRange.Copy Destination:=.Range(NameArea) Exit Do Else Application.Calculate SortRange.Sort Key1:=SortRange.Range("A1"), _ Header:=xlNo, Orientation:=xlLeftToRight End If Loop '------------------------------------------------------------ '班長以外の転記 'CopyDataCheckを呼び出し、コピー範囲と名前定義範囲の 'データが重複していないか調べ、 '重複していなければコピー範囲を転記 '重複していたら並べ替える CountOfCopy = 0 For Each Target In .Range(NameArea) Do If CopyDataCheck(CopyRange:=CopyRange, _ CheckRange:=.Range(NameArea), _ CheckPosition:=-1) = False Then CopyRange.Copy Destination:=Target.Offset(0, -4) CountOfCopy = CountOfCopy + 1 Exit Do Else Application.Calculate With SortRange With .Resize(, .Columns.Count - 1).Offset(, 1) .Sort Key1:=.Range("A1"), Header:=xlNo, _ Orientation:=xlLeftToRight End With End With End If Loop If CountOfCopy = .Range(NameArea).Cells.Count Then Exit For End If Application.Calculate With SortRange With .Resize(, .Columns.Count - 1).Offset(, 1) .Sort Key1:=.Range("A1"), Header:=xlNo, _ Orientation:=xlLeftToRight End With End With Next Target Next NameArea For Each NameArea In Array("Kumi1", "Kumi2", "Kumi3", "Kumi4") .Range(NameArea).Value = _ "LD:" & .Range(NameArea).Range("A1").Value Next NameArea End With '------------------------------------------------------------ 'エクセルの設定及びオブジェクト変数の後始末 NameListRange.Offset(-1).Clear Application.Calculation = xlCalculationAutomatic Set CopyRange = Nothing Set SortRange = Nothing Set LeaderRange = Nothing Set NameListRange = Nothing Set mySht = Nothing Set NewBook = Nothing End Sub Function CopyDataCheck(ByVal CopyRange As Range, _ CheckRange As Range, CheckPosition As Long) As Boolean '指定されたコピー範囲とチェック範囲(名前定義した範囲の領域) 'に同じデータがあるか、総当りで調べて結果を返す関数 '全部同じ=>True、同じではない=>Falseを返す Dim CopyR As Range 'コピー範囲の各セル Dim CheckR As Range 'チェック範囲の各セル Dim SameDataCount As Long '同じデータ数 Dim i As Long '列カウンタ '------------------------------------------------------------ '重複データはないと回答(仮定)しておく CopyDataCheck = False For Each CheckR In CheckRange If CheckR.Offset(, CheckPosition).Value <> "" Then SameDataCount = 0 For Each CopyR In CopyRange For i = 1 To CopyRange.Cells.Count If CopyR.Value = CheckR.Offset(, _ i * CheckPosition).Value Then SameDataCount = SameDataCount + 1 End If Next i Next CopyR If SameDataCount = CopyRange.Cells.Count Then 'すべて重複データだったと回答する CopyDataCheck = True Exit Function End If End If Next CheckR End Function
その他の回答 (2)
- OtenkiAme
- ベストアンサー率77% (69/89)
こんにちは。 > 1点目は、この動作を組2、組3、組4においても繰り返したいのです > が、4回繰り返して書く方法以外に、簡潔な書き方があれば教えてくだ > さい。 前回も書きましたが、質問者さんだけが分かる情報を持っていて、回答 者側が分からない状態では、回答しようがありません。 一般的には、共通する処理をサブルーチン化して呼び出すような処理にするか、 Sub Hogehoge() Call Hogehoge2("組1") Call Hogehoge2("組2") Call Hogehoge2("組3") Call Hogehoge2("組4") End Sub Sub Hogehoge2(ByVal NameRange As String) Dim a As Range For Each a In Sheets("組合せ").Range(NameRange) 処理 Next a End Sub For Each .. In .. Nextを使うことになると思います。 Sub Hogehoge() Dim XXX As Variant Dim a As Range For Each XXX In Array("組1","組2","組3","組4") For Each a In Sheets("組合せ").Range(XXX) 処理 Next a Next XXX End Sub のような書き方ができると思います。 質問者さんが「簡潔な書き方」を何を指しておっしゃっているのか分か りませんが、同じような処理を4回繰り返して書かないことが「簡潔な書 き方」だとすれば、まず、4回繰り返して処理を書いて、共通できる処理 とそうでない処理を割り出すことから始めたら如何でしょうか。 > 2点目は、………のRange("B2")の値が、4組の中で繰り返し出てこない > ようにしたいのです。 コピー範囲と、貼付済み範囲のデータが同じかどうか総当たりで調べ、同 じにならなくなるまでコピー範囲の並べ替えを繰り返してから、貼付すれ ばいいのではないでしょうか。
- OtenkiAme
- ベストアンサー率77% (69/89)
こんにちは。 とりあえず、提示されたコードを編集してみました。 Select、Selectionを使っていないので読みやすいと思います。 具体的なデータが提示されていないので動作の検証は、質問者さんが行ってください。 組1だけでなく、組2、3,4も行いたいとのことですが、データをどのように使うのかが回答したい側に伝わっていないので回答は控えさせていただきます。 編集したコードを見れば、質問者さんがどこをどう修正すればいいのか、見えてくるのではないかと思います。 ではでは。 Sub 名簿を編集() Dim a As Range '名簿シートの1行目に=RAND()関数を入れる。2行目に名簿を作成する。 '組合せシートの$AI$1, $AI$3, $AC$1, $AC$3の4つのセルに”組1”という名前を定義 '名簿シートのB2セルの人を班長として固定。組合せシートの”組1”(4箇所)に貼り付ける Sheets("名簿").Range("B2").Copy Destination:=Sheets("組合せ").Range("組1") '名簿シートのC2セルから2行の最後までのデータをランダムに並べ替え、C2からF2をコピー、貼付け For Each a In Sheets("組合せ").Range("組1") Sheets("名簿").Range("C1:I2").Sort _ Key1:=Sheets("名簿").Range("C1"), Order1:=xlAscending, _ Header:=xlGuess, OrderCustom:=1, MatchCase:=False, _ Orientation:=xlLeftToRight, SortMethod:=xlPinYin, _ DataOption1:=xlSortNormal Sheets("名簿").Range("C2:F2").Copy Destination:=a.Offset(0, -4) Next a '名簿シートの全てのデータをランダムに並び替え。 Sheets("名簿").Range("B1:I2").Sort _ Key1:=Sheets("名簿").Range("C1"), Order1:=xlAscending, _ Header:=xlGuess, OrderCustom:=1, MatchCase:=False, _ Orientation:=xlLeftToRight, SortMethod:=xlPinYin, _ DataOption1:=xlSortNormal End Sub
補足
早速、正確で親切な回答をありがとうございます。 いつも質問の仕方が悪く叱られているので、大変うれしく思いました。本当にありがとうございました。 早速動作の確認をしましたが、命令が簡潔で、スピードも速くできました。 ついでに、もう2点ほど教えていただきたいことがあるのですが、よろしければお願いいたします。甘えてしまって申し訳ありません。 1点目は、この動作を組2、組3、組4においても繰り返したいのですが、4回繰り返して書く方法以外に、簡潔な書き方があれば教えてください。 2点目は、 Sheets("名簿").Range("B2").Copy Destination:=Sheets("組合せ").Range("組1") のRange("B2")の値が、4組の中で繰り返し出てこないようにしたいのです。 どうぞよろしくお願いいたします。
お礼
何度もありがとうございました。なにもかもお世話になってありがとうございます。思ったよりレベルが高く、戸惑っていますが、教えていただいたコードにじっくり取り組んで、完成させたいと思います。本当にありがとうございました。これまでこれほど責任をもって取り組んでいただいたことはなく、感動しています。お返事が遅くなって申し訳ありませんでした。