質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
VBA

VBAはオブジェクト指向プログラミング言語のひとつで、マクロを作成によりExcelなどのOffice業務を自動化することができます。

Office 365

Office 365は、マイクロソフトが販売している企業向けクラウドベースのグループウエアサービス。電子メールや予定表、Webサイト構築、オンラインストレージ、ビデオ会議などビジネスで必要な機能を備えています。クラウドサービスのため、自社での専用サーバーの設置の必要がないことが特徴です。

Q&A

解決済

4回答

3550閲覧

VBA 配列 一番若い日付 調べる方法

tttkkk

総合スコア38

VBA

VBAはオブジェクト指向プログラミング言語のひとつで、マクロを作成によりExcelなどのOffice業務を自動化することができます。

Office 365

Office 365は、マイクロソフトが販売している企業向けクラウドベースのグループウエアサービス。電子メールや予定表、Webサイト構築、オンラインストレージ、ビデオ会議などビジネスで必要な機能を備えています。クラウドサービスのため、自社での専用サーバーの設置の必要がないことが特徴です。

0グッド

1クリップ

投稿2021/04/06 12:52

配列の中に日付やその他数値を含む値が格納されており、その配列の中から一番若い日付を取得する方法を教えて頂けないでしょうか。

在庫の管理上、コードと賞味期限およびその個数を管理しております。
そのリストをdictionaryで取得し、それぞれのコードをキーとして賞味期限と個数をアイテムに配列形式で格納しております。

そこで特定のキーに格納されてるアイテムである賞味期限と個数の配列から一番若い日付を取得する方法はございますでしょうか。

配列形式のアイテムに対して、worksheet関数のminを使用しましたが、
①賞味期限のシリアル値よりも個数の方が数値としては小さいため一番少ない個数が取得されてしまうこと、
②そもそもアイテムの配列形式として格納されている日付が数値として認識されず、個数が全て空欄だったとしても0が返される
という2点が問題として起こってしまいました。

以下にサンプルコードとExcelのスクショを掲載致しましたので、参考にして頂けますと幸いです。
なお、今回は便宜上、キーとなる特定のコードは 11行目 の 6018 と致しました。

VBA

1Sub dictionaryArray() 2 3Dim myDictionary As Object 4Set myDictionary = CreateObject("Scripting.Dictionary") 5 6Dim foundCd As Range 7Set foundCd = Cells.Find(what:="コード", lookat:=xlWhole) 8Dim i As Long, j As Long, n As Long 9Dim BBarray() As Variant 10 11'コードをKeyとして、コードに連なる賞味期限、個数をItemとして配列形式に格納 12For i = foundCd.Row + 1 To Cells(Rows.Count, foundCd.column).End(xlUp).Row 13 'UBoundでエラーがでないように再定義。 14 ReDim BBarray(0) As Variant 15 For j = foundCd.column + 1 To foundCd.End(xlToRight).column 16 n = UBound(BBarray) + 1 17 ReDim Preserve BBarray(n) 18 BBarray(n) = Cells(i, j).Value 'BBarray(0)には何も格納されていないことになる。 19 Next j 20' dictionaryにコードとその賞味期限、個数を登録。 21 myDictionary.Add Cells(i, foundCd.column).Value, BBarray 22Next i 23 24'dictionaryのKey、Itemをインデックスで指定できるように変数に格納。 25Dim BBkey As Variant, BBitem As Variant 26BBkey = myDictionary.keys 27BBitem = myDictionary.items 28 29Dim cd As Long 30cd = 6018 31 32'cdのBBkeyのインデックスを調べる。 33Dim cdIndex As Long 34For cdIndex = 0 To UBound(BBkey) 35 If (BBkey(cdIndex) = cd) Then 36 Exit For 37 End If 38Next cdIndex 39 40Debug.Print Application.WorksheetFunction.Min(BBitem(cdIndex)) 41 42End Sub

イメージ説明

お手数おかけしますが、教えて頂けますと幸いです。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

xail2222

2021/04/06 14:10 編集

データの持ち方を変えるのはありですか?って書いてあった。返答きたから、書き直しました!
tttkkk

2021/04/06 14:06

私の理解が足らず、申し訳ないのですが、 データの持ち方を変えるとはどういうことでしょうか。 このファイルのレイアウト以外は考えたことが無く、もしマクロを走らせる上で、改善した方が良い部分がありましたら、その点も考慮したいとは思います。
xail2222

2021/04/06 14:11

シートのレイアウトは変える必要はないとおもいます。シートのデータの読み込んでプログラムの変数として持つときに、その持ち方を変えるのはどうですか?という意味です。
xail2222

2021/04/06 14:12

とりあえず、一つ回答入ってるので私も回答として、参考になるかどうかわからないけど サンプルプログラムを提示してみます。
guest

回答4

0

ベストアンサー

下記のような方針でコーディングしてみました。

  1. 日付と個数という異なるデータを一つの配列に入れるのがそもそも無理があるので、それぞれ別の配列に格納する。

 

  1. 日付はminでは0になるようなので、シリアル値で配列に格納する。シリアル値は Value2 プロパティで取得できます。

 

  1. 2つの配列はArray関数で一つの配列にまとめて、Dictionary に格納する。

vba

1Sub dictionaryArray() 2 Dim myDictionary As Object 3 Set myDictionary = CreateObject("Scripting.Dictionary") 4 5 Dim foundCd As Range 6 Set foundCd = Cells.Find(what:="コード", lookat:=xlWhole) 7 8 Dim leftCol As Long, rightCol As Long 9 leftCol = foundCd.Column 10 rightCol = foundCd.End(xlToRight).Column 11 12 Dim kigen() As Variant, kosu() As Variant 13 14 'コードをKeyとして、コードに連なる賞味期限、個数をItemとして配列形式に格納 15 Dim i As Long, j As Long 16 For i = foundCd.Row + 1 To Cells(Rows.Count, foundCd.Column).End(xlUp).Row 17 ReDim kigen((rightCol - leftCol) / 2) 18 ReDim kosu((rightCol - leftCol) / 2) 19 20 For j = leftCol + 1 To rightCol Step 2 21 kigen((j - leftCol) \ 2) = Cells(i, j).Value2 22 kosu((j - leftCol) \ 2) = Cells(i, j + 1).Value 23 Next j 24 ' dictionaryにコードとその賞味期限、個数を登録。 25 myDictionary.Add Cells(i, leftCol).Value, Array(kigen, kosu) 26 Next i 27 28 Dim cd As Long 29 cd = 3808 30 31 If myDictionary.exists(cd) Then 32 kigen = myDictionary(cd)(0) 33 Debug.Print "最古賞味期限:" & CDate(Application.WorksheetFunction.Min(kigen)) 34 Else 35 Debug.Print "コード" & cd & "は見つかりません。" 36 End If 37 38End Sub

投稿2021/04/06 15:06

hatena19

総合スコア33715

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

tttkkk

2021/04/07 13:02

ご丁寧にありがとうございます!。 お1つ質問になるのですが、今回賞味期限を取得したいということで、最後の方のコードが If myDictionary.exists(cd) Then kigen = myDictionary(cd)(0) Debug.Print "最古賞味期限:" & CDate(Application.WorksheetFunction.Min(kigen)) Else Debug.Print "コード" & cd & "は見つかりません。" End If と書いて頂けております。 これを今度個数を取得したいとなった場合には kigen = myDictionary(cd)(0) の部分をどのように変更するべきなのでしょうか。 現状、個数を取得して活用する予定はございませんが、 dictionaryの理解を深めたいと思い、お伺い致しました。 教えていただけますでしょうか。
hatena19

2021/04/07 13:11 編集

myDictionary(cd)(1) で個数の配列を取得できます。 DictionaryのItemに賞味期限の配列と個数の配列を Array(kigen, kosu) で一つの配列にしています。
tttkkk

2021/04/08 12:27

なるほど。 本当にご丁寧にありがとうございます。 非常に勉強になりました。
guest

0

賞味期限と個数が順番に入っているのなら、
そこから賞味期限の要素だけ取り出してから比較すればいいのでは。

VBA

1Dim arr 2arr = BBitem(cdIndex) 3Redim arrKigen(1 To Ubound(arr) / 2) 4 5Dim k 6For k = 1 To Ubound(arrKigen) 7 arrKigen(k) = arr(k * 2 - 1) 8Next 9 10Debug.Print Application.WorksheetFunction.Min(arrKigen) 11

投稿2021/04/07 13:26

jinoji

総合スコア4585

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

tttkkk

2021/04/08 12:26

申し訳ありません。 記載して頂いたコードで走らせてみたのですが、最後の Application.WorksheetFunction.Min(arrKigen) の部分でどしても0が変えさせてしまいました。 確かにarrkigenの予想としては、仰る通り日付しか入っていないのですが、0が返されていまいます。 これは配列であるBBitemの時点で賞味期限(日付)も個数(数値)を一緒に格納してしまっているので、 このBBitemから賞味期限(日付)だけを抜き出しても、VBAでは日付とは認識されたないということになるのでしょうか。
jinoji

2021/04/08 12:46

xail2222さん,hatena19さんの回答にあるように セルからの取得時にValue2を使う、もしくは変数への格納時にcLngする、とすればきっと大丈夫な気が。 たとえば、上のコードを ​arrKigen(k) = cLng(arr(k * 2 - 1)) とするとかでどうですか。
tttkkk

2021/04/10 03:45

やはり一旦どこかで日付に変換するという処理が必要なのですね。 日付の扱い方は難しいとよく言われますが、その所以がよく分かった気がします。 ご回答して頂きありがとうございました。
tttkkk

2021/04/10 03:46

日付に ではなく 日付を でした。 失礼致しました。
guest

0

よくわかってないけど回答します!
(1)日付のminは取れないみたいなのでClngで数値にしてminとってその後表示とかする時にCDateする!

(2)賞味期限と個数がdcitionaryの値として同じ配列に入っているのをやめて
dictionary:コード→[dictionary:賞味期限→個数] という形にする

サンプルコードを書いてみます。

VBA

1 2Public Sub test() 3 ' データ準備 4 Dim tDic As Scripting.Dictionary 5 Set tDic = New Scripting.Dictionary 6 Dim tDicSub As Scripting.Dictionary 7 Set tDicSub = New Scripting.Dictionary 8 tDic.Add 1000, tDicSub 9 tDicSub.Add CLng(CDate("2021/2/5")), 1 10 tDicSub.Add CLng(CDate("2021/2/3")), 2 11 tDicSub.Add CLng(CDate("2021/2/4")), 3 12 tDicSub.Add CLng(CDate("2021/2/6")), 4 13 14 ' 最小の日付(整数値)を求める 15 Dim tMinLngDate As Long 16 tMinLngDate = Excel.WorksheetFunction.Min(tDic.Item(1000).Keys) 17 18 ' 最小の日付とその個数を表示 19 Debug.Print CDate(tMinLngDate) & ":" & tDic.Item(1000).Item(tMinLngDate) 20End Sub 21

という感じなのですが、使えないでしょうか!

あ、後参考までに

VBA

1Dim BBkey As Variant, BBitem As Variant 2BBkey = myDictionary.keys 3BBitem = myDictionary.items 4 5Dim cd As Long 6cd = 6018 7 8'cdのBBkeyのインデックスを調べる。 9Dim cdIndex As Long 10For cdIndex = 0 To UBound(BBkey) 11 If (BBkey(cdIndex) = cd) Then 12 Exit For 13 End If 14Next cdIndex 15 16Debug.Print Application.WorksheetFunction.Min(BBitem(cdIndex))

とやってますが、これは

VBA

1Dim cd As Long 2cd = 6018 3Debug.Print Application.WorksheetFunction.Min(myDictionary.item(cd))

これと同じことです! のはずです!

投稿2021/04/06 14:16

編集2021/04/06 14:20
xail2222

総合スコア1497

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

tttkkk

2021/04/08 12:37

私自身のコードを修正して頂いてありがとうございます。 ご指摘して頂いた通りで、無駄に for cdIndex を回していることに気付けておりませんでした。 またdictionaryにさらにdictionaryを追加するという方法も教えて頂きありがとうございます。 私自身まだdictionaryを勉強し始めて理解が浅く、dictionaryを二重するというのは、私自身がコードを振り返った時の可読性の観点から少し控えようと思います。 しかしdictionaryにdictionaryを登録するということは全く思いつかなかったアイデアでしたので、よりdictionaryの理解を深めたのち、チャレンジ致します。
guest

0

MinIfsが使えないかな、と考えたけど、引数がRangeでないといけないっぽいので、何かひと工夫が必要ですね。
たとえばこんな感じ?(試してはいないですが。)

VBA

1 ReDim BBarray(0) As Variant 2 Dim dataRange As Range 3 Set dataRange = Range(foundCd.Offset(, 1), foundCd.End(xlToRight)) 4 BBarray(0) = WorksheetFunction.MinIfs(dataRange, dataRange, ">40000") 5

投稿2021/04/06 13:49

jinoji

総合スコア4585

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問