• ベストアンサー
※ ChatGPTを利用し、要約された質問です(原文:お助け下さい、プログラミングの分かる方!!)

プログラミングでの重複データのリストアップ方法と最新日付の取得方法について教えてください

このQ&Aのポイント
  • プログラミングでデータ一覧の重複チェックと最新日付の取得方法について教えてください。
  • データ一覧の中で重複していないデータと重複したデータのうち最新の日付のものをリストアップする方法についてお知りの方がいらっしゃいました。
  • また、重複しているデータに色をつける方法についてもお教えいただきたいです。

質問者が選んだベストアンサー

  • ベストアンサー
  • Randomize
  • ベストアンサー率70% (38/54)
回答No.2

条件付きで重複行を処理したい場合はDictionaryオブジェクトの使用をお勧めします。 まずはプログラムソースから '=====プログラムここから===== Public Sub DoSyuukei() Dim objDicNameList As Object Dim NowReadRow As Long, MaxReadRow As Long Dim NowReadCol As Long, MaxReadCol As Long Dim NowIndex As Long, MaxIndex As Long Dim NowWriteRow As Long Dim objOutputRange As Range Dim objSrcSheet As Worksheet Dim varRangeWriteData() As Variant Dim varResultArray As Variant Dim strTemp As String '=====設定部分===== '元のデータを読み込みたいシートを指定 Set objSrcSheet = ThisWorkbook.Worksheets("Sheet1") '結果を出力する部分の左上を指定 Set objOutputRange = ThisWorkbook.Worksheets("Sheet2").Range("A1") '=====プログラム本体===== '今回のミソ、Dictionaryオブジェクトの宣言 Set objDicNameList = CreateObject("Scripting.Dictionary") '念のため全消去(なくてもOK) objDicNameList.RemoveAll '最終行を取得 MaxReadRow = objSrcSheet.Cells(objSrcSheet.Rows.Count, 1).End(xlUp).Row '2行目から順に内容を解析していく(1行目はタイトルだから行わない) For NowReadRow = 2 To MaxReadRow '重複をチェックするのは顧客名と製品名の2個なので、この2個をタブ文字でつないだ文字列で重複チェックを行う strTemp = objSrcSheet.Cells(NowReadRow, 2).Value & vbTab & objSrcSheet.Cells(NowReadRow, 3).Value 'この作成した文字がすでに出てきたかをチェックする If objDicNameList.Exists(strTemp) = True Then '登録されている場合は、登録されているデータの日付を読みだしてチェックする '同じ日付である場合は下にある方が優先(「>=」を「>」にすると上にある方が優先になります) If objSrcSheet.Cells(NowReadRow, 1).Value >= objDicNameList.Item(strTemp)(0) Then '今読んでいるデータの方が新しい場合のみデータを再登録する(さらに重複回数を+1する) objDicNameList.Item(strTemp) = Array(objSrcSheet.Cells(NowReadRow, 1).Value, NowReadRow, objDicNameList.Item(strTemp)(2) + 1) Else 'データが新しくない場合は重複回数を+1するのみ objDicNameList.Item(strTemp) = Array(objDicNameList.Item(strTemp)(0), objDicNameList.Item(strTemp)(1), objDicNameList.Item(strTemp)(2) + 1) End If Else '登録されてない場合 '登録されていない場合は新規に登録する (日付,データのあるExcelの行番号,重複回数)の3個のデータを格納する objDicNameList.Add strTemp, Array(objSrcSheet.Cells(NowReadRow, 1).Value, NowReadRow, 0) End If Next '調査結果に従って結果を作成する MaxIndex = objDicNameList.Count '何種類データがあったかを取得 '元のデータは何列データがあるかを取得( =3 などのように手で指定してもOK) MaxReadCol = objSrcSheet.Cells(1, objSrcSheet.Columns.Count).End(xlToLeft).Column '結果を入れる用の作業用データ領域を作成(こうすることで高速化が可能) '見出し行のため1行多く設定する。更に重複であることを記入する場所のため、列も1列多く宣言する ReDim varRangeWriteData(1 To MaxIndex + 1, 1 To MaxReadCol + 1) 'タイトル行を複写 For NowReadCol = 1 To MaxReadCol varRangeWriteData(1, NowReadCol) = objSrcSheet.Cells(1, NowReadCol).Value Next varRangeWriteData(1, MaxReadCol + 1) = "重複回数" '重複回数の列タイトルを作成 '集計した結果を変数に吐き出しする varResultArray = objDicNameList.Items 'objdicNameListの中に記録した行のデータを元にセルのデータを作成していく NowWriteRow = 2 '1行目は見出し行なので2行目から開始 For NowIndex = 1 To MaxIndex '元シートから読み込むべき行番号を取り出す NowReadRow = varResultArray(NowIndex - 1)(1) '読み出すべき行番号を元にその場所のデータを複写する For NowReadCol = 1 To MaxReadCol varRangeWriteData(NowWriteRow, NowReadCol) = objSrcSheet.Cells(NowReadRow, NowReadCol).Value Next '重複データであった場合は重複回数を書きだす If varResultArray(NowIndex - 1)(2) > 0 Then varRangeWriteData(NowWriteRow, MaxReadCol + 1) = varResultArray(NowIndex - 1)(2) End If '書きだす場所を次の行に変更 NowWriteRow = NowWriteRow + 1 Next '作成したデータを貼り付けるのにどのくらいの大きさのセル範囲が必要かを計算して指定する With objOutputRange.Worksheet.Range(objOutputRange, objOutputRange.Offset(UBound(varRangeWriteData, 1) - 1, UBound(varRangeWriteData, 2) - 1)) '作成したデータをExcelに貼り付け .Value = varRangeWriteData '.Sort "顧客名", , "製品名", , , , , xlYes '結果をソートしたければコメント解除して編集してください。左は顧客と製品名でソート End With '出したものはお片づけ Set objOutputRange = Nothing Set objDicNameList = Nothing Set objSrcSheet = Nothing End Sub '=====プログラムここまで===== Dictionaryオブジェクトを用いることにより、Exists(調べたい文字)とするだけで過去にその文字を登録したことがあるかを一発で調べることができます。詳しく知りたい場合は、[vba dictionary]さらに原理を知りたい場合は[連想配列]のあたりで検索をするといいでしょう。参考になるURLを3つほど紹介しておきます。 http://www.eurus.dti.ne.jp/~yoneyama/Excel/vba/vba_dictionary.html http://officetanaka.net/excel/vba/tips/tips80.htm http://www.php-labo.net/tutorial/php/hash.html (言語がVBでなくPHPだが、絵の雰囲気で解説するので良ければ参考に) さらにもう1個、これは説明しているサイトが少ないですが、Dictionaryオブジェクトは格納できるのは値1個だけではなく、配列をそのまま格納することができてしまいます。Array(○○,△△)のように。それを用いて最新の日付はいつとか何回重複したかなどを実現しています。 文字数制限の関係で詳しく解説出来なかったですが、今後の参考とステップアップの糧になれば幸いです。

zilchcoo
質問者

お礼

誠にありがとうございました。 一言、完璧!!でした。 本当にありがとうございます。 検証するのに時間がかかり、 お礼のメールが遅れてしまい、申し訳ありませんでした。 でも、Dictionaryオブジェクトは難しいですね。 本当にこれだけ丁寧に解説頂いてやっと 利用できたという感じです。 これからもすこしづつ頑張っていきたいと思いますので、 機会がありましたら、またお助け下さい。 宜しくお願い致します。

すると、全ての回答が全文表示されます。

その他の回答 (1)

  • imogasi
  • ベストアンサー率27% (4737/17070)
回答No.1

(1)していしなければ、関数でも回答が出そうだが、式は長く複雑な式になる。 (2)VBAでも2列の条件を満たす行を抜き出すのでも、難しい。2列を結合した列を新たに作れば出来ないことは無いが。 ACCESSなどでのSQLなら2条件、3条件でもAND条件でSELECTはたやすい。エクセルからSQLを使えるから、中級者ならそちらを考える人もいるかも。(MSクエリ)。 またばらばらだと顧客+製品で、同じものの日付の新しいものも抜き出すのも簡単ではない。 ーー 一番簡単と思うのは、VBAを使っての「ソート法」だろう。 (1)まずシートのコピーを別に作る。以下コピー側で話する。(元のシートを温存するため) (2)下記条件でソート   顧客名列   製品名列   日付列 この優先順序で昇順に指定してソート。 すると顧客名+製品名で同じものは近接の行に集り、その中で日付的に違うものは最新の行が最後に来る。 ただし日付入力は日付シリアル値であるとする。それなら日付は正整数の大小が日図家日付の前後と同じ意味になる。 これ判りますか。VBAでなく、エクセルの基礎的知識です。 ーー 例データ Sheet2 日付 顧客名 製品名 担当者 価格 個数 合計金額 1月4日 近藤さん C 担当者C 100 300 30000 1月1日 田中さん A 担当者A 100 100 10000 1月5日 田中さん A 担当者D 200 100 20000 1月7日 田中さん A 担当者F 100 100 10000 1月2日 田中さん B 担当者B 200 100 20000 1月9日 田中さん C 担当者B 200 100 20000 1月3日 鈴木さん B 担当者C 300 200 60000 1月6日 鈴木さん B 担当者C 150 400 60000 1月8日 鈴木さん C 担当者A 50 500 25000 ーー 標準モジュールに Sub test01() Dim sh1, sh2 Set sh1 = Worksheets("Sheet2") Set sh2 = Worksheets("Sheet3") d1 = sh1.Range("A65536").End(xlUp).Row MsgBox d1 k = 2 '2行目から書き出し '--- For i = 2 To d1 - 1 x = sh1.Cells(i, "B") & sh1.Cells(i, "C") y = sh1.Cells(i + 1, "B") & sh1.Cells(i + 1, "C") '直下行のキー If x = y Then '直下行とキーが同じなら何もしない、読み飛ばし Else '直下行とキーが変わっていたら、自身の行の各列を書き出し For j = 1 To 7 sh2.Cells(k, j) = sh1.Cells(i, j) Next j k = k + 1 End If Next i '--最終行で,iはFor Nextを抜けたとき1つ進んでいるので For j = 1 To 7 sh2.Cells(k, j) = sh1.Cells(i, j) Next j End Sub ーーー 結果 Sheet3 見出しの作成とA列の日付書式の設定は省略している。補ってください。手動でもよかろう。 2011/1/4 近藤さん C 担当者C 100 300 30000 2011/1/7 田中さん A 担当者F 100 100 10000 2011/1/2 田中さん B 担当者B 200 100 20000 2011/1/9 田中さん C 担当者B 200 100 20000 2011/1/6 鈴木さん B 担当者C 150 400 60000 2011/1/8 鈴木さん C 担当者A 50 500 25000 多分この方法が、行数が1番少ないだろう。

zilchcoo
質問者

お礼

返答頂いたのですが、 私の想像した結果になりませんでした。 また次の機会に是非ご協力いただければ 幸いです。 ありがとうございました。

すると、全ての回答が全文表示されます。

関連するQ&A