Excel VBA質問箱 IV

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

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


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

【70689】COUNTIF関数の処理スピードを高める方法について kakinoki 11/12/16(金) 17:42 発言[未読]
【70691】Re:COUNTIF関数の処理スピードを高める方法... kanabun 11/12/16(金) 18:56 発言[未読]
【70693】Re:COUNTIF関数の処理スピードを高める方法... kanabun 11/12/16(金) 19:32 発言[未読]
【70694】Re:COUNTIF関数の処理スピードを高める方法... kanabun 11/12/16(金) 19:35 発言[未読]
【70696】Re:COUNTIF関数の処理スピードを高める方法... kakinoki 11/12/17(土) 1:03 質問[未読]
【70697】Re:COUNTIF関数の処理スピードを高める方法... kanabun 11/12/17(土) 8:52 発言[未読]
【70782】Re:COUNTIF関数の処理スピードを高める方法... kakinoki 11/12/30(金) 11:27 お礼[未読]
【70740】Re:COUNTIF関数の処理スピードを高める方法... Jaka 11/12/22(木) 10:00 発言[未読]

【70689】COUNTIF関数の処理スピードを高める方法...
発言  kakinoki  - 11/12/16(金) 17:42 -

引用なし
パスワード
   COUNTIF関数を使って「名前」と「名前+生年月日」の重複をカウントする下記のコードを作りました。結果は出るのですが処理に時間がかかりすぎるため、処理時間を短縮できる別な方法があれば教えていただきたいのですが。初心者なので基本的なコードしかかけていません。ご指導よろしくお願いいたします。
下記での処理時間は(私のPCで)約10分かかります(データ数30000行)
Sub 重複データチェック()
  Dim mySheet1 As String
  mySheet1 = "meibo"
  
  Worksheets(mySheet1).Select
  'A列に名前 B列に生年月日
  Range("C2:C65000").Formula = "=IF($A2="""","""",A2&B2)"  '名前+生年月日" 
  Range("D2:D65000").Formula = "=IF($A2="""","""",COUNTIF($A$2:$A$65000,A2))" '名前の重複数
  Range("E2:E65000").Formula = "=IF($A2="""","""",COUNTIF($C$2:$C$65000,C2))" '名前+生年月日の重複数
  
  Range("A2").Select
End Sub

【70691】Re:COUNTIF関数の処理スピードを高める方...
発言  kanabun  - 11/12/16(金) 18:56 -

引用なし
パスワード
   ▼kakinoki さん:
>COUNTIF関数を使って
Application.Calculation を 手動(xlCalculationManual)にすれば、多少速くなるかも
しれないけれど、根本的な解決ではないので、
他の方法 (Dictionaryオブジェクトを使って重複をカウントしたほうがいいと思います。

【70693】Re:COUNTIF関数の処理スピードを高める方...
発言  kanabun  - 11/12/16(金) 19:32 -

引用なし
パスワード
   >▼kakinoki さん:
>他の方法 (Dictionaryオブジェクト)を使って重複をカウント

こんな感じです

'--------------------------------- 標準モジュール
Option Explicit

Sub Try1()
  Dim r As Range
  Dim v, i As Long, n As Long
  Dim u, ss As String
  Dim dic As Object 
  Dim t!      '時間計測用
  t = Timer()
  
  Set dic = CreateObject("Scripting.Dictionary")
  Set r = Range("A2", Cells(Rows.Count, 1).End(xlUp))
  v = r.Resize(, 2).Value
  n = UBound(v)
  ReDim u(1 To n, 1 To 3)
  For i = 1 To n
    If Len(v(i, 1)) > 0 Then
      dic(v(i, 1)) = dic(v(i, 1)) + 1
      ss = v(i, 1) & v(i, 2)
      u(i, 1) = ss
      dic(ss) = dic(ss) + 1
    End If
  Next
  ReDim rev(1 To n, 1 To 2)
  For i = 1 To n
    If Len(v(i, 1)) > 0 Then
      u(i, 2) = dic(v(i, 1))
      u(i, 3) = dic(u(i, 1))
    End If
  Next
  r.Offset(, 2).Resize(, 3).Value = u
    
  Debug.Print Timer() - t
End Sub

30,000行のデータに対し実行した結果は  0.46 秒でした。

【70694】Re:COUNTIF関数の処理スピードを高める方...
発言  kanabun  - 11/12/16(金) 19:35 -

引用なし
パスワード
   失礼
途中で宣言している

>  ReDim rev(1 To n, 1 To 2)

どこでも使ってません。削除ねがいます。

【70696】Re:COUNTIF関数の処理スピードを高める方...
質問  kakinoki  - 11/12/17(土) 1:03 -

引用なし
パスワード
   kanabunさん 早速のご指導ありがとうございました
おかげさまで抜群の早出処理できるようになりました
ただ、生年月日が空白のデータが相当数あり、この時には
「名前」と「名前+生年月日」が同じになり、2とカウント
してしまいます。ご指導いただいた内容をA列(名前)だけの
重複数、とC列(名前+生年月日)だけの重複数カウントに
なるような変更を工夫してみましたが、出来ませんでした
ご指導いただけたらと思います。よろしくお願いいたします。

▼kanabun さん:
>>▼kakinoki さん:
>>他の方法 (Dictionaryオブジェクト)を使って重複をカウント
>
>こんな感じです
>
>'--------------------------------- 標準モジュール
>Option Explicit
>
>Sub Try1()
>  Dim r As Range
>  Dim v, i As Long, n As Long
>  Dim u, ss As String
>  Dim dic As Object 
>  Dim t!      '時間計測用
>  t = Timer()
>  
>  Set dic = CreateObject("Scripting.Dictionary")
>  Set r = Range("A2", Cells(Rows.Count, 1).End(xlUp))
>  v = r.Resize(, 2).Value
>  n = UBound(v)
>  ReDim u(1 To n, 1 To 3)
>  For i = 1 To n
>    If Len(v(i, 1)) > 0 Then
>      dic(v(i, 1)) = dic(v(i, 1)) + 1
>      ss = v(i, 1) & v(i, 2)
>      u(i, 1) = ss
>      dic(ss) = dic(ss) + 1
>    End If
>  Next
>  ReDim rev(1 To n, 1 To 2)
>  For i = 1 To n
>    If Len(v(i, 1)) > 0 Then
>      u(i, 2) = dic(v(i, 1))
>      u(i, 3) = dic(u(i, 1))
>    End If
>  Next
>  r.Offset(, 2).Resize(, 3).Value = u
>    
>  Debug.Print Timer() - t
>End Sub
>
>30,000行のデータに対し実行した結果は  0.46 秒でした。

【70697】Re:COUNTIF関数の処理スピードを高める方...
発言  kanabun  - 11/12/17(土) 8:52 -

引用なし
パスワード
   ▼kakinoki さん:
>おかげさまで抜群の早出処理できるようになりました
>ただ、生年月日が空白のデータが相当数あり、この時には
>「名前」と「名前+生年月日」が同じになり、2とカウント
>してしまいます。
なるほど、そういう(生年月日が空白の)ケースを考えないと
いけなかったですね
以下で試してみてください。

Sub Try2()
  Dim r As Range
  Dim v, i As Long, n As Long
  Dim u, ss As String
  Dim dic As Object
  
  Dim t!
  t = Timer()
  
  Set dic = CreateObject("Scripting.Dictionary")
  Set r = Range("A2", Cells(Rows.Count, 1).End(xlUp))
  v = r.Resize(, 2).Value
  n = UBound(v)
  ReDim u(1 To n, 1 To 3)
  For i = 1 To n
    If Len(v(i, 1)) > 0 Then
      dic(v(i, 1)) = dic(v(i, 1)) + 1
      If Len(v(i, 2)) > 0 Then  '◆ 追加 B列入力のチェック
        ss = v(i, 1) & v(i, 2)
        u(i, 1) = ss
        dic(ss) = dic(ss) + 1
      End If
    End If
  Next
  
  For i = 1 To n
    If Len(v(i, 1)) > 0 Then
      u(i, 2) = dic(v(i, 1))
      If Len(v(i, 2)) > 0 Then  '◆ 追加 B列入力のチェック
        u(i, 3) = dic(u(i, 1))
      End If
    End If
  Next
  r.Offset(, 2).Resize(, 3).Value = u
    
  Debug.Print Timer() - t
End Sub

【70740】Re:COUNTIF関数の処理スピードを高める方...
発言  Jaka  - 11/12/22(木) 10:00 -

引用なし
パスワード
   なんとなく感じた事。

>  'A列に名前 B列に生年月日
>  Range("C2:C65000").Formula = "=IF($A2="""","""",A2&B2)"  '名前+生年月日"

Range("C2:C65000").Value = Range("C2:C65000").Value

>  Range("D2:D65000").Formula = "=IF($A2="""","""",COUNTIF($A$2:$A$65000,A2))" '名前の重複数

Range("D2:D65000").Value = Range("D2:D65000").Value

>  Range("E2:E65000").Formula = "=IF($A2="""","""",COUNTIF($C$2:$C$65000,C2))" '名前+生年月日の重複数

Range("E2:E65000").Value = Range("E2:E65000").Value

って、都度値に変換したらどうなるのだろうか?と...。
Dictionaryより遅いとは思いますけど。

【70782】Re:COUNTIF関数の処理スピードを高める方...
お礼  kakinoki  - 11/12/30(金) 11:27 -

引用なし
パスワード
   kanabunさん
ありがとうございました。スピーディに処理できるようになりました。
COUNTIF関数以外の方法が分からずそれに頼っていましたが、マクロでも
すごい方法があるのですね。少しずつ勉強していきます。ありがとうございました。PCが故障したためお礼が遅くなり申し訳ありませんでした。

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