複数の日付の中から一番早い/遅い日付を取得する
特定の列に複数の日付が入力されています。この中から一番早い(古い)日付と遅い(新しい)日付を取得したいです。
という質問をいただきました。質問者様は配列も勉強したい様ですのでコード内で使っていく事にします。
実は複数の日付の中から一番早い日/遅い日を取得するのは非常に簡単です。ネックになるのは配列です。
VBAの中でも配列は難しい方ですよね。
確かに配列は難しいです。配列を使うとコーディングの難易度が少し上がります。
開発時のペースは落ちる事になりますね。他にも配列には考えないといけないことが何点かあります。
- 配列自体が難しい(単純に理解できない)
- 配列内の値にソートをかける為のコードを理解するのが難しい(バブルソートなど)
- 格納する値の型を考えるのが難しい(数値型なのか文字列なのか、日付型なのかなど)
色々悩み事はありますが「まずは手を動かす」ことが重要です。
配列は慣れです。シンプルな事例を沢山作る事で自然に使いこなせるようになります。
では配列を使って複数の日付の中から一番早い日/遅い日を取得していきましょう。すぐに事例を見たい方はこちら。
MAXメソッドとMINメソッドは使いません
本事例はWorksheetFunctionオブジェクトのMAXメソッドとMINメソッドを使うと結果は出ます。
しかし今回は使いません。理由は以下3つです。
- 配列を使いたいから
- 自分のやりたい事をコードに置き換える為に思考面のトレーニングも兼ねたいから
- ローカルウインドウを見ながらコーディングをするトレーニングにも使いたいから
MAXメソッドとMINメソッドはエクセルのワークシート関数(MAX関数、MIN関数)と同じ結果を返します。
こうなるとワークシート関数をVBAで使うだけになってしまいます。これだけではちょっと面白くないです。
質問者様と会話した際に希望されていた事と私が必要だと思ったトレーニングができるようにコードを考えました。
関連記事
カテゴリー「配列」のリンクはこちらです。
関連書籍
配列について解説されている書籍を紹介します。
配列について
配列について詳しく解説されているサイトや事例を探してみたのですが「コレ」というものが見つけられませんでした。
参考までにMicrosoftのドキュメントを用意しました。多少知識のある人は理解できるかもしれません。
配列は、値を格納するための多くのコンパートメントを持つ 1 つの変数
Microsoft:配列の使用より抜粋
参考:2次元配列を使ってみる
私も2次元配列について解説しています。配列は使ってみないと分からないので体験型の記事にしました。
記事内にコピペで使えるコードを用意しています。配列を使用したコードと未使用のコードの速度差を感じてください。
配列を分かりやすく解説【検索にも使える】VBAの2次元配列で作業の高速化を実現させる
文字には型があります
多くのプログラミング言語では文字を扱う時に何らかの型を指定します。VBAも文字に対して型を指定します。
型を指定する理由は「安定したプログラムを書く」為です。
プログラミングは英文字を文章のように書いていると思われがちですが規則性があります。
この規則性を保つ為には入力する文字や出力される文字がどんな型で用意されるのかを決めておく必要があります。
1つ例を紹介します。DateSerialという関数です。数値型のパラメータを与えることで日付型の文字列を生成します。
Dateserial関数
この関数は数値を与えると日付を返してくれる関数です。早速構文とパラメータを紹介します。まずは構文です。
続いてパラメータです。設定するパラメータは以下3つです。全て数値型のIntegerで文字を用意します。
最後は戻り値です。パラメータとして指定した年、月、日を Variant (Date) 型の文字を戻り値として返します。
戻り値はDate型の変数で受けることができるうえVariant型の配列の中でDate型としても受ける事ができます。
使用例
たとえば「2024/05/19」というDate型の文字を指定する際は以下の様に関数にパラメータを渡す事になります。
文字に型を指定することで環境が安定します
事例で紹介した様にパラメータとして渡す型、戻り値として返される型が分かっていると良い事が沢山あります。
たとえば「エラーの回避」です。あるパラメータが数値型だと分かっていたら文字列型の値を格納しませんよね。
これだけでもエラーの回避につながります。エラーが回避できれば安定したプログラミング環境を用意することができます。
プログラミングで扱う文字には型があるという事について事例を紹介させていただきました。
事例(複数の日付の中から一番早い/遅い日付を取得)
配列を使って複数の日付の中から一番早い日/遅い日を取得していきましょう。
ワークシート
B列に連続で日付を用意しました。数は17,000弱です。連続なので一番上は一番早い日付で最後が一番遅い日付です。
日程の並びはランダムにしていません。理由は数が欲しかった為です。作業を簡単にする為に連続で日付を用意しました。
B列に並んだ日付を1つずつ確認したうえで一番早い日をセルE2、遅い日をセルE3に出力します。
ワークシートから操作できるようにボタンも用意しました。
手作業でフィルターを使ってソートを行ってみるとスムーズには動かないデータ量です。
これぐらいのデータ量があれば配列の能力を確認するには十分です。
コード
コードはこちらです。
Sub day()
'変数を定義
Dim first_day As Date
Dim last_day As Date
Dim ws As Worksheet
Dim idx As Long
Dim days As Variant
'各種変数に値を格納
Set ws = Worksheets("Sheet1")
days = ws.Range(ws.Cells(6, 2), ws.Cells(Cells(Rows.Count, 2).End(xlUp).Row, 2))
first_day = days(1, 1)
last_day = days(1, 1)
'配列内の日付を1つずつ調べる
For idx = LBound(days) To UBound(days)
'first_dayより後の日程ですか?
If days(idx, 1) > first_day Then
'last_dayより後の日程ですか?
If days(idx, 1) > last_day Then
'last_dayに設定
last_day = days(idx, 1)
Else
End If
Else
'first_dayに設定
first_day = days(idx, 1)
End If
Next
'セルに値を入力
ws.Cells(2, 5) = first_day
ws.Cells(3, 5) = last_day
End Sub
結果
実行ボタンを押すとセルE2、E3に値が入ります。
実行時間は1秒かかりません。配列を使っているのですぐに結果が表示されます。
日付が規則的に並んでいなくても実行時間は変わりません。
解説
このコードは用意されたすべての値に目を通して確認していくというコードです。
一見時間がかかりそうな作業ですが配列が解決してくれます。ポイントは2つです。
- 配列へ値を格納する方法
- 一番早い日と遅い日を探す為のアルゴリズム
ひとつずつ説明します。
1_配列へ値を格納する方法
配列には1つずつ値をセットして・・・というのが一般的なのですが「面倒」ですよね。
できるだけ簡単にコーディングしたいのでこの方法を使います。
まずはVariant型で変数を1つ用意します。私はdaysという変数をつくりました。
そのあとRangeオブジェクトを使って日付が入力されている範囲をdaysに代入します。
この作業だけで必要な情報を一括で配列に格納できます。続いてVBEのローカルウインドウをご覧ください。
ローカルウインドウで変数の値を確認してみる
ローカルウインドウで変数daysを展開してください。2次元配列として値が格納されている事がわかります。
2次元配列ですので複数列の情報もこの様に一括で配列に格納することができます。
青背景で白文字の行をご覧ください。配列の1次元目には16740個の値が格納されていることがわかります。
続いて2次元目です。「1to1」なので1列分の情報が格納されていることがわかります。
複数列の値を配列に格納した際はこの2次元目の値が取得した列数と同じだけ増える事になります。
たとえば3列分の値を取得すると「1 to 3」という表記になります。
次は格納する文字の型ついて説明します。
Variant型の配列ですので文字、数値、日付何でも格納できます。(列毎に値の型は揃えておく事を推奨します)
2_一番早い日と遅い日を探す為のアルゴリズム
フローにすると分かります。一番早い日と一番遅い日を取り出すのはそんなに難しくないんですよ。
2回比較(条件分岐)するだけです。あとは画像のようなフローをプロシージャ内に再現することで作業完了です。
用意した日程の中で一番早い日(古い日)と一番遅い日(新しい日)を見つけるだけです。
確認する日付が沢山あっても配列内の値を使うので一瞬で終わります。
まとめ
複数の日付の中から一番早い日付と遅い日付を取得する方法を紹介しました。
ロジック自体は簡単なのであとは「思いつくかどうか」だけです。こういった思考方法はトレーニングが必要です。
普段の仕事をフローに落とし込むというトレーニングを繰り返す事で自然と思いつくようになってきます。
さらにおすすめのトレーニング方法はPowerAutomateなどの無料のRPAツールを使う事です。
RPAツールは自動化したい業務に対してフローを作成しフローに対してコマンドを当て込んでいくという仕様です。
この作業ができる様になると自分の仕事をフローに置き換える能力が格段にあがります。
興味がありましたらお試しください。