Excel VBA質問箱 IV

当質問箱は、有志のボランティア精神のおかげで成り立っています。
問題が解決したら、必ずお礼をしましょうね。
本サイトの基本方針をまとめました。こちら をご一読ください。

投稿種別の選択が必要です。ご注意ください。
迷惑投稿防止のため、URLの入力を制限しています。ご了承ください。


2007 / 13645 ツリー ←次へ | 前へ→

【70530】データを検索したり行削除したりしたい かさねるくん 11/11/26(土) 11:07 質問[未読]
【70531】Re:データを検索したり行削除したりしたい Hirofumi 11/11/26(土) 12:23 発言[未読]
【70532】Re:データを検索したり行削除したりしたい Hirofumi 11/11/26(土) 12:26 発言[未読]
【70533】Re:データを検索したり行削除したりしたい かさねるくん 11/11/26(土) 16:10 発言[未読]
【70535】Re:データを検索したり行削除したりしたい Hirofumi 11/11/26(土) 16:41 発言[未読]
【70534】現在のコード かさねるくん 11/11/26(土) 16:27 発言[未読]
【70536】Re:現在のコード Hirofumi 11/11/26(土) 16:54 発言[未読]
【70537】Re:現在のコード Hirofumi 11/11/26(土) 19:52 回答[未読]
【70538】Re:現在のコード Hirofumi 11/11/26(土) 20:33 発言[未読]
【70542】ありがとうございます かさねるくん 11/11/27(日) 13:21 お礼[未読]

【70530】データを検索したり行削除したりしたい
質問  かさねるくん  - 11/11/26(土) 11:07 -

引用なし
パスワード
   今は力技でやっているのですが、データ量が数千件になってから速度が遅くなりすぎてしまったので改善したいと思い、質問させて頂きます。

データは1行単位で下記のようになっています
A列  B列  C列   D列   E列・・・
番号 種別 内容1 内容2 内容3
番号 種別 内容1 内容2 内容3
番号 種別 内容1 内容2 内容3
番号 種別 内容1 内容2 内容3

この種別毎に件数をカウントしたり、選択した種別以外のデータを行で削除したいのです(複数の種別を選択することもあります)
種別はアルファベットで始まる英数5桁ですが、大文字小文字が混ざっています
種別は先頭の1文字だけで選別して大丈夫です(K1235とk4278も同じ種別)

現在やっているやり方は、For文で1行毎にデータを見て、種別の先頭文字が選んだ物なら最終列にマークを入れ、件数に+1し、最終行まで繰り返します
最終行まで終わったら、マークの無い列を1行1行Selectして削除しています

これと同じ動作をもう少し早く行うことはできないでしょうか?
ScreenUpdatingはFalseにしています

【70531】Re:データを検索したり行削除したりしたい
発言  Hirofumi  - 11/11/26(土) 12:23 -

引用なし
パスワード
   >この種別毎に件数をカウントしたり、選択した種別以外のデータを行で削除したいのです
>(複数の種別を選択することもあります)

種別の選択はどの様に行っているのですか?

>現在やっているやり方は、For文で1行毎にデータを見て、種別の先頭文字が選んだ物なら
>最終列にマークを入れ、件数に+1し、最終行まで繰り返します
>最終行まで終わったら、マークの無い列を1行1行Selectして削除しています
>
>これと同じ動作をもう少し早く行うことはできないでしょうか?

配列と整列を使えば出来ると思いますよ?

【70532】Re:データを検索したり行削除したりしたい
発言  Hirofumi  - 11/11/26(土) 12:26 -

引用なし
パスワード
   それと、今使っているコードもUpした方が善いと思いますよ

【70533】Re:データを検索したり行削除したりしたい
発言  かさねるくん  - 11/11/26(土) 16:10 -

引用なし
パスワード
   >種別の選択はどの様に行っているのですか?

種別の選択はユーザーフォームにチェックボックスを並べ、VBAでチェックボックスの値がTrueか否かで判断しています
種別の大文字小文字はLCaseを使用して統一しています


>配列と整列を使えば出来ると思いますよ?

Variant型の変数にArray関数で種別の列をまるごと入れる感じで良いのでしょうか?
整列はソートすることとは違うのですか?

【70534】現在のコード
発言  かさねるくん  - 11/11/26(土) 16:27 -

引用なし
パスワード
   For i = 1 to Range("B1").End(xlDown).Row
If checkbox1.Value = True Then
 If LEFT(LCase(Cells( i, 2).Value),1) = "a" Then
  Cells( i, 20) = "a"
  Cnt1 = Cnt1 + 1
 End If
Else
 If checkbox2.Value = True Then
  If LEFT(LCase(Cells( i, 2).Value),1) = "b" Then
  Cells( i, 20) = "b"
  Cnt2 = Cnt2 + 1
  End If
 Else
  If checkbox3.Value = True Then
  If LEFT(LCase(Cells( i, 2).Value),1) = "c" Then
   Cells( i, 20) = "c"
   Cnt3 = Cnt3 + 1
  End If
  End If
 End If
End If
Next i

Cells( Range("B1").End(xlDown).Row + 1, 20) = "end"

TextBox1.Value = Cnt1
TextBox2.Value = Cnt2
TextBox3.Value = Cnt3

For i = 1 to Range("B1").End(xlDown).Row
If Cells( i, 20).Value = "end" Then
 Exit Sub
End If
If Cells( i, 20).Value = "" Then
 Rows(i).Select
 Selection.Delete Shift:=xlUp
 i = i - 1
End If
Next i

【70535】Re:データを検索したり行削除したりしたい
発言  Hirofumi  - 11/11/26(土) 16:41 -

引用なし
パスワード
   ▼かさねるくん さん:
>>種別の選択はどの様に行っているのですか?
>
>種別の選択はユーザーフォームにチェックボックスを並べ、VBAでチェックボックスの値がTrueか否かで判断しています
>種別の大文字小文字はLCaseを使用して統一しています
>
>
>>配列と整列を使えば出来ると思いますよ?
>
>Variant型の変数にArray関数で種別の列をまるごと入れる感じで良いのでしょうか?
>整列はソートすることとは違うのですか?

種別のカウントを何処に取るかが解らないのですが?
こんな手順で行ったら善いかと?

B列種別の列を配列に取得します
次に、B列の行数と同じ行数の配列を用意します
データの配列を上から見て行って
該当する行の配列の要素にマークを入れます
此れを最終行まで行います
次にこの結果を書き込んだ配列をListの最終列の後ろに出力します
次に、出力した列(マークの入って居る列)をKey列としてListを整列(ソート)します
すると、マークが無い行はListの下に集まります
次に、この集まった行を一気に削除します
以上

【70536】Re:現在のコード
発言  Hirofumi  - 11/11/26(土) 16:54 -

引用なし
パスワード
   ▼かさねるくん さん:
>For i = 1 to Range("B1").End(xlDown).Row
> If checkbox1.Value = True Then
> If LEFT(LCase(Cells( i, 2).Value),1) = "a" Then
>  Cells( i, 20) = "a"
>  Cnt1 = Cnt1 + 1
> End If
> Else
> If checkbox2.Value = True Then
>  If LEFT(LCase(Cells( i, 2).Value),1) = "b" Then
>  Cells( i, 20) = "b"
>  Cnt2 = Cnt2 + 1
>  End If
> Else
>  If checkbox3.Value = True Then
>  If LEFT(LCase(Cells( i, 2).Value),1) = "c" Then
>   Cells( i, 20) = "c"
>   Cnt3 = Cnt3 + 1
>  End If
>  End If
> End If
> End If
>Next i
>
>Cells( Range("B1").End(xlDown).Row + 1, 20) = "end"
>
>TextBox1.Value = Cnt1
>TextBox2.Value = Cnt2
>TextBox3.Value = Cnt3
>
>For i = 1 to Range("B1").End(xlDown).Row
> If Cells( i, 20).Value = "end" Then
> Exit Sub
> End If
> If Cells( i, 20).Value = "" Then
> Rows(i).Select
> Selection.Delete Shift:=xlUp
> i = i - 1
> End If
>Next i

UserFromのチェックボックスは幾つ在るのですか?
また、TextBoxの数は幾つ在るのですか?
其々の、CheckBox、TextBoxが表す物は何ですか?

例として
CheckBox1は種別の頭が「a」を表します


CheckBox126は種別の頭が「z」を表します

TextBox1.Valueは種別の頭が「a」のカウントを表示します


TextBox26.Valueは種別の頭が「z」のカウントを表示します

など

【70537】Re:現在のコード
回答  Hirofumi  - 11/11/26(土) 19:52 -

引用なし
パスワード
   私ならこんなコードにしますかな?
幾らか速いと思います

UserFormに以下のコントロールが配置されている物とします
1、CheckBox1〜CheckBox126でCaptionが比較する文字と同じ文字が設定されている物とします
 上記の場合、★1のコードを使います
 もし、CheckBoxのCaptionが比較する文字と違う文字の場合
 デザインモードでCheckBoxのTagプロパティに比較する文字を設置します
 例えば、CheckBox.Tag="a"の様にします
 ※実際のCheckBoxの数をコードの定数宣言
  'CheckBoxの数
  Const clngCheck As Long = 26
 で設定して下さい
2、TextBox1〜TextBox4を配置します
 ※実際のTextBoxの数をコードの定数宣言
  'TextBoxの数
  Const clngText As Long = 4
 で設定して下さい
3、CommandButtan1:実行ボタンを配置します

次に、操作するListはA〜T列迄で列見出しは無い物とします

UserFormを表示して、CheckBoxにチェックをいれCommandButton1を押すと
もし、チェックの数がclngText以下ならカウントと削除が行われます

UserFormのコードモジュールに以下を記述して下さい

Private Sub CommandButton1_Click()

  'Listのデータ列数(A列〜T列)
  Const clngColumns As Long = 20
  'Listの中のKeyと成る列位置(基準列AからのB列列Offset)
  Const clngKey As Long = 1
  'CheckBoxの数
  Const clngCheck As Long = 26
  'TextBoxの数
  Const clngText As Long = 4
  
  Dim i As Long
  Dim j As Long
  Dim lngRows As Long
  Dim rngList As Range
  Dim rngResult As Range
  Dim rngMark As Range
  Dim vntData As Variant
  Dim vntKeys As Variant
  Dim vntResult As Variant
  Dim lngCount As Long
  Dim strProm As String
  
  'Listの先頭セル位置を基準とする(データ先頭)
  Set rngList = ActiveSheet.Range("A1")
  
  '種別の値を取得
  ReDim vntKeys(1 To 2, 1 To clngText)
  lngCount = 0
  For i = 1 To clngCheck
    If Controls("CheckBox" & i).Value Then
      lngCount = lngCount + 1
      If lngCount > clngText Then
        strProm = "チェックを出来る数は" & clngText & "個までです"
        GoTo Wayout
      End If
      '★1比較するKeyがコントロールのCaptionと同じなら
      'Captionから配列に移します
      vntKeys(1, lngCount) = Controls("CheckBox" & i).Caption
      '★2比較するKeyをコントロールのTagから配列に移します
'      vntKeys(1, lngCount) = Controls("CheckBox" & i).Tag
    End If
  Next i
      
  With rngList
    '行数の取得
    lngRows = .Offset(Rows.Count - .Row, _
        clngKey).End(xlUp).Row - .Row + 1
    If lngRows <= 1 And IsEmpty(.Value) Then
      strProm = "データが有りません"
      GoTo Wayout
    End If
    '列データを配列に取得
    vntData = .Offset(, clngKey).Resize(lngRows + 1).Value
    '結果用配列を確保
    ReDim vntResult(1 To lngRows, 1 To 1)
  End With
  
  'Key列に就いて繰り返し
  lngCount = 0
  For i = 1 To lngRows
    'Keyの配列の先頭〜最終まで
    For j = 1 To UBound(vntKeys, 2)
      '先頭の1文字がKeyと一致するなら
      If StrComp(Left(vntData(i, 1), 1), _
          vntKeys(1, j), vbTextCompare) = 0 Then
        Exit For
      End If
    Next j
    '一致した場合
    If j <= UBound(vntKeys, 2) Then
      '種別のカウントを取る
      vntKeys(2, j) = vntKeys(2, j) + 1
      '結果用配列の現在位置にマークを入れる
      vntResult(i, 1) = vntKeys(1, j)
    Else
      'マークを入れ入れない行をカウント
      lngCount = lngCount + 1
    End If
  Next i
  
  '取得した種別のカウントをTextBoxに転記
  For i = 1 To clngText
    Controls("TextBox" & i).Value _
        = vntKeys(1, i) & " = " & vntKeys(2, i)
  Next i
  
  With rngList
    '結果をListの最終行と最終行1列前に出力
    .Offset(, clngColumns).Resize(lngRows).Value = vntResult
    '選択した種別以外の物が有るなら
    If lngCount > 0 Then
      If MsgBox("選択された種別以外を削除しますか?", _
          vbInformation + vbYesNo) = vbYes Then
        'Listをマークを入れた行で整列
        .Resize(lngRows, clngColumns + 1).Sort _
            Key1:=.Offset(, clngColumns), Order1:=xlAscending, _
            Header:=xlNo, OrderCustom:=1, MatchCase:=False, _
            Orientation:=xlTopToBottom, SortMethod:=xlStroke
        'マークの無い行を削除
        .Offset(lngRows - lngCount) _
            .Resize(lngCount).EntireRow.Delete
      End If
    End If
  End With
  
  strProm = "処理が完了しました"

Wayout:

  Set rngList = Nothing
  Set rngResult = Nothing
   
  MsgBox strProm, vbInformation
     
End Sub

【70538】Re:現在のコード
発言  Hirofumi  - 11/11/26(土) 20:33 -

引用なし
パスワード
   ごめん
以下の★印を追加変更して下さい

      End If
      '★1比較するKeyがコントロールのCaptionと同じなら
      'Captionから配列に移します
      vntKeys(1, lngCount) = Controls("CheckBox" & i).Caption
      '★2比較するKeyをコントロールのTagから配列に移します
'      vntKeys(1, lngCount) = Controls("CheckBox" & i).Tag
    End If
  Next i
  ReDim Preserve vntKeys(1 To 2, 1 To lngCount) '★追加

   ・
   ・
  '取得した種別のカウントをTextBoxに転記
'  For i = 1 To clngText
  For i = 1 To UBound(vntKeys, 2) '★変更
    Controls("TextBox" & i).Value _
        = vntKeys(1, i) & " = " & vntKeys(2, i)
  Next i

【70542】ありがとうございます
お礼  かさねるくん  - 11/11/27(日) 13:21 -

引用なし
パスワード
   返信が遅れて申し訳ございません
おかげさまで待ち時間を短くすることが出来ました

2007 / 13645 ツリー ←次へ | 前へ→
ページ:  ┃  記事番号:
2610219
(SS)C-BOARD v3.8 is Free