- ベストアンサー
このようなVBAを作りたいのですが
以下のようなデータがあります。 各セルの値は1~100までのランダムな値が入っています。 使用している列はAからFまでです。 例示すると、 A列 B列 C列 D列 E列 F列 1 24 75 69 34 2 55 66 47 28 92 53 13 21 63 32 47 61 44 3 17 81 49 36 以下続く ような形です。 そして、A列に1が200回出てきたら、そこまでのデータを(AからF列まで全てのデータ) を新たなシート1にコピーしたいのです。 この作業を繰り返したいのです。 次回 A列に1が400回出たところまでのデータを新たなシート2にコピー。 次々回 A列に1が600回 出たところまでのデータを新たなシート3にコピー。 {続く} 最終回 1が200の倍数丁度あるとは限らないので、空白になったら、そこまでのデータを新たなシートXにコピー。 といった感じです。 A列に1が何回出てくるかを基準に、データを分割するのが目的です。 言葉不足なので簡易化した例を挙げると、 1が2回出たら…という条件だとします。 A列 →新シート1のA列 新シート2のA列 新シート3のA列 2 2 6 2 1 1 7 1 3 3 1 1 1 8 6 5 7 1 1 8 5 1 2 1 のようにデータを分割したいのです。 普段、マクロを使ってデータから数値を取ることはするのですが、ある一定の範囲を新たなシートにコピーといった作業はしたことがないので、どのようなVBAを書けばいいのか見当がつきません。 分かる方、お手数をおかけして申し訳ないのですが、よろしくお願いします。
- みんなの回答 (3)
- 専門家の回答
質問者が選んだベストアンサー
こんにちは。 >新たなシートにコピーといった作業はしたことがないので、 >新シート1のA列 新シート2のA列 新シート3のA列 私には、"新シート1" とかいう設定自体が新たな名前をつけると解釈しました。新たなブックに移すにしても、そんなに手間ではないと思います。 仕組みを簡単に説明すると、1で、オートフィルタを掛けて、勘定して、セルの行番号を記録していけば数えるのは難しくありません。数万行でも、たぶん数秒で終わってしまうと思います。 一応、コピーした行数と、1の数だけは確認しました。 '標準モジュール Sub NumbersCopy() Dim i As Long Dim j As Long Dim k As Long Dim myRow As Long Dim LastRow As Long Dim c As Variant Dim s As Integer Dim cnt As Integer Dim flg As Boolean Dim shtCnt As Integer Dim adrs() As Long Dim acSheet As Worksheet '設定 Const UNIT As Integer = 200 '区切り単位 Const SHNAME As String = "新シート" 'シート名/ただし、:, などは使えません shtCnt = Worksheets.Count Set acSheet = ActiveSheet 'オートフィルタはしていないことを条件とします。 If acSheet.AutoFilterMode Then acSheet.AutoFilterMode = False '1を数える With acSheet If .Range("A1").Value = 1 Then .Rows(1).Insert .Range("A1").Value = "Dum" flg = True End If '最終行を求める(挿入後) LastRow = .Range("A65536").End(xlUp).Row With .Range("A1", .Range("A65536").End(xlUp)) .AutoFilter Field:=1, Criteria1:="1" For Each c In .SpecialCells(xlCellTypeVisible) ReDim Preserve adrs(i) adrs(i) = c.Row i = i + 1 Next c .AutoFilter End With End With 'シートを予め作る cnt = Int((UBound(adrs()) + 1) / UNIT) '余りが出ている場合 If LastRow > adrs(UBound(adrs())) Then cnt = cnt + 1 Worksheets.Add after:=Worksheets(shtCnt), Count:=cnt For s = shtCnt + 1 To Worksheets.Count Worksheets(s).Name = SHNAME & CStr(s - shtCnt) Next s '初期値 If flg Then k = 2 Else k = 1 End If Do j = j + UNIT shtCnt = shtCnt + 1 If j > UBound(adrs) + 1 Then With Worksheets(shtCnt) acSheet.Rows(k & ":" & LastRow).Copy .Range("A1") End With Else myRow = adrs(j) With Worksheets(shtCnt) 'Fまで acSheet.Rows(k & ":" & myRow).Resize(, 6).Copy .Range("A1") End With End If k = myRow + 1 Loop While Worksheets.Count >= shtCnt + 1 If flg Then acSheet.Rows(1).Delete End If Set acSheet = Nothing End Sub
その他の回答 (2)
- misatoanna
- ベストアンサー率58% (528/896)
> 各セルの値は1~100までのランダムな値が入って「います」。 つまり、都度入力される数字で判断するのではなく、既に全体が入力 済みのシートに対して処理するということで解釈しました。 とりあえず、簡易化された表(1が2回出たら)の場合です。 200回の場合は、★の行を If cnt = 200 Then に書き換えるわけで すが、200ともなると、テストデータ作成とマクロ実行後の結果のチェ ックが大変なので、検証していません。 Sub Test() Dim sh As String, i As Integer, rw As Integer, cnt As Integer Application.ScreenUpdating = False sh = ActiveSheet.Name i = 1 rw = 1 Do While Sheets(sh).Cells(i, 1) <> "" If Sheets(sh).Cells(i, 1) = 1 Then cnt = cnt + 1 If cnt = 2 Then '★ Sheets.Add Type:="ワークシート" ActiveSheet.Name = "Until " & i ActiveSheet.Move after:=Sheets(Sheets.Count) Sheets(sh).Rows(rw & ":" & i).Copy _ Destination:=Sheets("Until " & i).Rows(1) rw = i + 1 cnt = 0 End If i = i + 1 Loop Sheets.Add Type:="ワークシート" ActiveSheet.Name = "Until " & i ActiveSheet.Move after:=Sheets(Sheets.Count) Sheets(sh).Rows(rw & ":" & i).Copy _ Destination:=Sheets("Until " & i).Rows(1) Application.ScreenUpdating = True End Sub
お礼
素晴らしいプログラムありがとうございます! まだまだVBA初心者なので全くアイデアが浮かびませんでした。 本当に助かります! misatoannaさんのプログラムを見てどのような構造になっているか理解し、更にVBAを勉強したいと思います。 改めて,ありがとうございました!
- imogasi
- ベストアンサー率27% (4737/17069)
質問では1が所定回数加わると、初めからのデータを別シートへ写すような表現になっている。実例では前回移した以後のこれまでのデータになっている。たぶん実例の方だろう。 ーー これはA列に1が所定回数入力されたら、すぐに所望の処理をするのを希望ですか。 こんな、回答者にパズルを解かす(本質問は課題の丸投げタイプですよ)ような方式をやめて、データが全部入力し終わったら、処理する(バッチ処理)か、A列で 所定回数だけ1が現れたら、(COUNTIF関数でセルに1の件数をだし、気づいて)、処理のコマンドボタンを押すとかが良いのではないですか。処理が重くなったりチェンジイベントは扱いにくいと思うが。
お礼
非常に丁寧なプログラムをありがとうございます! Wendy02さんがお書きくださった内容を理解し、いずれは自分で作れるようになりたいと思います。 お手数をおかけして申し訳ございません。 そして、本当にありがとうございました!