[[20150112095914]] 『ExcelVBAで重複データを調べランダムに数字を作成』(fairlady) ページの最後に飛ぶ

[ 初めての方へ | 一覧(最新更新順) | 全文検索 | 過去ログ ]

 

『ExcelVBAで重複データを調べランダムに数字を作成』(fairlady)

こちらのサイトはよく参考にしており、今回初の投稿になります。宜しくお願いいたします。
仕事でもExcelをよく使っていますが、まだまだスキルが足りないと思い、独学で学んでおります。
それにあたり、何かよい題材がないかと思い、たまに買う数字選択宝くじを思い浮かべ
自分で色々表を作成して、多少関数など使えるようになったのですが、如何せん
手作業では、沢山できた表を管理出来なくなってきました。そこで今まで敷居が高く、
避けてきたVBAを学ぼうと思い色々なサイトを探して、こんなコードをみつけて、
Excelで数字をランダムに作成し、自分で作った表の過去データと重複していないか
確認しようと思ったのですが、うまくコードが書けません。

沢山のサイトを調べたのですが、いきずまっての投稿になります。
そこで今回の質問内容ですが、

 1 Sheet1で数字を6個ランダムに100通り組合せを作る
 2 Sheet2に過去のデータをB2〜G2以下に毎回入れる

 ※ 1での作成時にSheet2の過去のデータと今までに出た組み合わせでないか判定
   のループをさせたいのだがここが分かりません。

そのコードがこちらになります。(恥ずかしいですがコメントは、覚える為に私が
書きましたので間違ってる事と思います)

Sub Main()

Dim r As Integer, c As Integer 整数を入れるInteger型(整数)範囲は、-32,768 〜 +32,767
Dim i As Integer, j As Integer, k As Integer  Long型(長整数)範囲は、-2,147,483,648 〜 +2,147,483,647
Dim LastRow As Integer 変数の宣言。出力先の行番号を格納する
Dim Rng As Range セル範囲の操作を行うため、Range型の変数
Dim Flg As Boolean FlgがTrueまたはFalseのいずれかを格納するときにブール型

Flg = True フラグを立てる=条件(真)
r = 2
c = 1
Cells.ClearContents セルのコメント値クリア

Do While r <= 101  条件式を満たすまで繰り返す処理
With Cells(r, 1) Withを使って主語(操作の対象)を省略する
.Value = r - 1 セルの指定方法
.Font.ColorIndex = 5 フォントの文字色を設定
End With 同じオブジェクトに対して複数の処理を実行する

'6つのランダム数字を振る
For c = 2 To 7
Cells(r, c).Value = Application.WorksheetFunction.RoundUp(Rnd() * 43, 0)
Next c

Set Rng = Range(Cells(r, 2), Cells(r, 7))
Rng.Sort _
key1:=Cells(r, 1), _
Order1:=xlAscending, _
Orientation:=xlLeftToRight

'同じ行に同一数値が無いかの判定
For c = 2 To 6
If Cells(r, c).Value = Cells(r, c + 1).Value Then
Rng.ClearContents
Flg = False
Exit For
End If
Next c

'この数値の6つが今までに出た組み合わせでないか判定
For k = r - 1 To 2 Step -1
i = 1
For c = 2 To 7
If Cells(r, c).Value <> Cells(k, c).Value Then
i = i * 0
End If
Next c

If i = 1 Then
Rng.ClearContents
Flg = False
Exit For
End If
Next k

'両方OKの場合次へ
If Flg = True Then
r = r + 1
ElseIf Flg = False Then
Flg = True
End If

Loop

Set Rng = Nothing

End Sub

なにせVBA初心者な者ですので、コードのコメントも教えてくれれば、助かります。
なにとか御教示頂けたら幸いです。

< 使用 Excel:Excel2007、使用 OS:Windows7 >


 まずはインデントを付けましょう。

 >Excelで数字をランダムに作成し、自分で作った表の過去データと重複していないか
 >確認しようと思ったのですが、うまくコードが書けません。 

 ちょっとだけ手直ししてみましたが、基本今のコードで動いていませんか?

 Option Explicit

 Sub LOTOSIX()
 '整数を入れる
 'Integer型Integer型の範囲は、-32,768 〜 +32,767
 'Long型の範囲は、-2,147,483,648 〜 +2,147,483,647
    Dim r As Long, c As Long  ' ★ 特に意識しないなら整数は Long にした方が無難。 2003 でも 65536 行まで使える。
    Dim i As Long, j As Long, k As Long

    Dim LastRow As Long '変数の宣言。出力先の行番号を格納する
    Dim Rng As Range 'セル範囲の操作を行うため、Range型の変数
    Dim Flg As Boolean  'FlgがTrueまたはFalseのいずれかを格納するときにブール型

    Flg = True  'フラグを立てる=条件(真)
    r = 2  'rは行?
    c = 1 'cは列?
    Cells.ClearContents 'セルのコメント値クリア

    Do While r <= 101  ' 条件式を満たすまで繰り返す処理
        With Cells(r, 1)  '同じオブジェクトに対して複数の処理を実行する
            .Value = r - 1  'セルの指定方法
            .Font.ColorIndex = 5  'フォントの文字色を設定
        End With

        '6つのランダム数字を振る
        For c = 2 To 7
            Cells(r, c).Value = Application.WorksheetFunction.RoundUp(Rnd() * 43, 0)
        Next c

        Set Rng = Range(Cells(r, 2), Cells(r, 7))
        Rng.Sort _
        key1:=Cells(r, 1), _
        Order1:=xlAscending, _
        Orientation:=xlLeftToRight

        '同じ行に同一数値が無いかの判定
        For c = 2 To 5  '★ 5 まで
            If Cells(r, c).Value = Cells(r, c + 1).Value Then
                Rng.ClearContents
                Flg = False
                Exit For
            End If
        Next c

        'この数値の6つが今までに出た組み合わせでないか判定
        For k = r - 1 To 2 Step -1
            i = 1  ' ★ これもフラグ?
            For c = 2 To 7
                If Cells(r, c).Value <> Cells(k, c).Value Then
                    ' i = i * 0  ' ★???
                    i = 0
                End If
            Next c

            If i = 1 Then
                Rng.ClearContents
                Flg = False
                Exit For
            End If
        Next k

        '両方OKの場合次へ
        If Flg = True Then
            r = r + 1
        ElseIf Flg = False Then
            Flg = True
        End If
    Loop
    Set Rng = Nothing
 End Sub

 EXCEL の機能に重複の削除というのもありますから、そういった機能を使うのも一法だと
 思います。
 後こういったときによく使うのは Dictionary でしょうか。
 この例は後ほど。
(Mook) 2015/01/12(月) 13:00

 ちょっと興味本位で作ってしまったので、あまり参考にならないかもしれませんが、
 こんな書き方もあるということで。

 Dictionary
http://www.eurus.dti.ne.jp/~yoneyama/Excel/vba/vba_dictionary.html

 SortedList
http://www.eurus.dti.ne.jp/~yoneyama/Excel/vba/vba_sortedlist.html

 Option Explicit

 Sub LotoSix()
    Cells.Clear

    Dim lotoDic
    Set lotoDic = CreateObject("Scripting.Dictionary")
    Dim nums
    Dim checkKey As String
    Do While lotoDic.Count < 100  ' 登録が100になるまで実行
        nums = CreateLoto()
        checkKey = Join(nums, "/")  ' 数字を 「/」でつなげた文字列を生成
        If lotoDic.Exists(checkKey) = False Then  ' 同じ数値が無ければ登録
            lotoDic(checkKey) = True
            Cells(lotoDic.Count, "A") = lotoDic.Count
            Cells(lotoDic.Count, "A").Font.ColorIndex = 5
            Cells(lotoDic.Count, "B").Resize(1, 6) = nums
        End If
    Loop
 End Sub

 Function CreateLoto()
    Dim DataList
    Set DataList = CreateObject("System.Collections.SortedList")

    Dim n As Long
    Do While DataList.Count < 6 ' 数字が6個になるまで実行
        n = Int(Rnd() * 43) + 1
        If DataList.Contains(n) = False Then  '  同じ数字がなければ登録
            DataList.Add n, n
        End If
    Loop

    ' 結果を Array にして返す。  (VBA では CopyTo が使えないようなので。)
    Dim res()
    ReDim res(DataList.Count)
    Dim r As Long
    For r = 0 To DataList.Count - 1
        res(r) = DataList.getByIndex(r)
    Next
    CreateLoto = res

    Set DataList = Nothing
 End Function

(Mook) 2015/01/12(月) 13:51


初めての投稿でしたので、何度か読み返していて編集をし直していました。早速のご返答有り難うございます。返答しようと恥ずかしくも確認もせず、再度編集で書き込んでいました。

wordで直しながら書いていた物をそのままコピーしたのでインデントしてませんでした。
なにせ色々付け刃的な所があるので、Integerで書いたのは、Longよりメモリの無駄な領域を確保しないと何処かのサイトで見かけたものでした。
今、色々調べたら、Integer型は2byte(16bit)領域に格納され、また、Long型は4byte(32bit)領域に格納される事が分かりました。
そのため、16bitのInteger型は、一度32bitに変換してから処理を行うとの事。
結果、PC内部での変換により、32bit領域のLong型の方が処理が早いとの事でしたのでLongを使います。

やはり、誰かに質問すると気がつかない所が見えてきます。

たしかにこのコードで、アクティブなSheet1で動きますが、sheet2でのデータを参照しながら
ループさせたい事でした。

(fairlady) 2015/01/12(月) 15:15


 >Integerで書いたのは、Longよりメモリの無駄な領域を確保しないと何処かのサイトで見かけたものでした。 
 の認識は誤ってはいませんが、CPUが貧弱で、メモリが少なったはるか昔のお話です。
 メモリが潤沢にあり、CPU が高速化された現在では、メモリや実行速度(変数の違いによる)
 はとるに足らないお話だと思います。

 それよりは、配列を使うとか、計算をつどしない(Calculation)や画面を更新しない
 (ScreenUpdating)などを制御する方が何千倍、何万倍も性能に寄与します。

 さて、本題ですが、Sheet1とSheet2 の具体的な使い方はどういったモノでしょうか。
 Sheet2 のデータというのは何でしょう?
(Mook) 2015/01/12(月) 15:24

コメント返信:

[ 一覧(最新更新順) ]


YukiWiki 1.6.7 Copyright (C) 2000,2001 by Hiroshi Yuki. Modified by kazu.