Excel (VBA)

Excel VBAに関するフォーラムです。
  • 掲示板への投稿には会員登録(無料)が必要です。会員登録がまだの方はこちら
  • 掲示板ご利用上のお願い」に反するご記入はご遠慮ください。
  • Q&A掲示板の使い方はこちらをご覧ください
トピックに返信
質問

 
(Windows 11 Home : Microsoft 365)
ビルのエアコンの修理日を格納する方法
投稿日時: 26/02/07 15:30:42
投稿者: humipinedesu

一覧で、縦に階数の番号、横の見出しで各部屋番号、2つ目の横の見出しに、部屋毎のエアコン(1〜複数個)の列があります。
階数毎の該当する部屋番号のエアコンのセルにフィルター交換した日付を入力します。
これをVBAで変数に保存したいのですが、階が複数、部屋が複数、各部屋のエアコンも複数ありうる場合、どうすればよいですか。変数の構造設計と、セットの仕方、取り出し方を教えてほしいです。クラスを使った方がいいのかなと思うのですが、そのやり方がわかりません。

回答
投稿日時: 26/02/08 23:06:47
投稿者: simple

返事もなく、こちらの受け止めが間違っていた気もしますので、いったん取り下げました。
改めてコメントします。

引用:
一覧で、縦に階数の番号、横の見出しで各部屋番号、2つ目の横の見出しに、部屋毎のエアコン(1〜複数個)の列があります。
階数毎の該当する部屋番号のエアコンのセルにフィルター交換した日付を入力します。
ここまでは分かります。特定の形式の表があって、フィルター交換日付を入力するのですよね、
引用:
これをVBAで変数に保存したいのですが、階が複数、部屋が複数、各部屋のエアコンも複数ありうる場合、どうすればよいですか。

どういう意味でしょうか。あらためて説明していただけないですか?
どういうことを実行したいのでしょうか。そしてどこに詰まっているのでしょうか。
決められたセルに入力するのではなく、別の形式で入力しやすいようにしたいということですか?
変数に保存したいというのは、何が目的ですか?まずそこから説明して頂けないですか?

投稿日時: 26/02/09 07:34:56
投稿者: humipinedesu

私がしたいことは、ビルの各階の、例えば、一階の行にある各部屋(列)のエアコンのセル(複数ありうる)に入力された日付を変数に入れて、それを、別の位置年間のエアコンフィルター交換実績一覧に入力していきたいのです。後者の一覧は、横の見出しが1月から12月まであり、縦の見出しに1F〜10Fまでの各部屋番号が入力してあります。一部屋に対して、複数のエアコンがある場合は、101号室の場合、101-1, 101-2...という風に見出しが書かれてあり、その各セルに、元の一覧から取得した日付をセットしていくわけです。
 
この場合に、各階(配列変数)に紐づいた部屋番号の配列変数、そして、その部屋番号の配列に紐づいた1つ目のエアコンの日付、2つ目のエアコンの日付をセットしていくと、後者の一覧に値を入れていく時に変数から取り出しやすいと思います。これを Do...Loopなどで繰り返ししていけば、効率的に値をセットするプログラムがかけます。
 
しかし、Excel vbaでは配列変数の中に配列変数はセットできず、Variant型にしなくてはいけないと思います。そして、これを階の配列、部屋の配列、日付の配列を持つクラスで実現するのか、または、クラスで作るよりも単にコーディングするだけでよいのか、
 
また、実際に作る場合にどのように作っていけば良いのか、イメージが出てこないのです。
 
これで、私の知りたいことが何かわかりますでしょうか?

回答
投稿日時: 26/02/09 08:39:12
投稿者: simple

説明不足が大分解消されたように思います。(当初の質問からはとても想像できませんよ。)
 
(1)
一覧表から別の形式の表に転記するという問題ですね?
一覧表の全データが対象ですか?それとも、最近にフィルタ交換した特定のものだけが対象ですか?
(まあ、それは応用としてそちらで適宜対応して下さい)
(2)
・現在の一覧表から、
    ・階、部屋番号、エアコン番号(連番)とそれに見合う
    ・フィルタ交換日
  は分かりますね。
・それを転記する際には、交換実績一覧表の何行目に書けばいいかがわかればいいわけですから、
  仮にA列に
    1階 101号室-1 などの文字列が入っているなら、
  A列に対してMATCH関数で調べれば何行目かわかりませんか?
・どの列に書くかはフィルタ交換日の月を調べればわかります。
 
(3)
MATCH関数がお気に召さなければ、dictionary(連想配列)を使って、
"1階 101号室-1" と 転記先の行番号
という対応関係を、交換実績一覧表から予め作成しておくとよいでしょう。
元の一覧表のデータから割り出した
階数、部屋番号、エアコン番号から"1階 101号室-1"形式の文字列を作成し、
それを基にdictionaryに照会して書き込み先の番号を求めることができます。
 
シートにフィルタ交換日ごとにひとつづつ書き込んでもよいですし、
予め配列を用意しておいて、いったん配列に書き込んだうえで、
最後に一括してシートに書き込んでもよいでしょう。
 
(4)
この説明で不明であれば、サンプルデータを表形式で提示されることをお薦めします。
(そうすればコードベースで話ができるでしょう。)
 
二つのシートを

    A       B       C       D
1
2
3
4
といった形式で示して下さい。(表は記入後、コードと言うボタンで修飾すると崩れにくいです)
・全データは不要で、サンプルデータで結構です。つまり架空のもので問題ありません。
・ただし、階数、部屋番号、エアコン番号などのキー情報の表示形式は、
  できるだけ実際に近いものにするとよいでしょう。
・また、両方のシートのデータの関係は整合的なものにして、検証に役立てられるものにして下さい。

回答
投稿日時: 26/02/09 21:00:13
投稿者: simple

反応ないので、メモした置いたものをアップして私の区切りとします。
 
●<現行一覧表(Sheet1)のレイアウト>

     A列  B          C         D             
1行       101        102       102           
2                    1         2             
3    1F   2026/1/10  2026/2/9  2026/2/9      
4    2F   2026/3/1   2026/1/20 2026/1/20     
5                                            
6                                            
7                                    

# C1:D1はセル結合されていても、コードで対応しているので問題なし
 
●<交換実績一覧表(Sheet2)のレイアウト>
      A   B         C          D         E  
1行   階  エアコン  1月        2月       3月
2     1F  101       2026/1/10
3     1F  102-1                2026/2/9
4     1F  102-2                2026/2/9
5     2F  101                           2026/3/1
6     2F  102-1     2026/1/20
7     2F  102-2     2026/1/20

■コード例は、以下。
Sub test()
    Dim ws1 As Worksheet, ws2 As Worksheet
    Dim dic     As Object
    Dim r$
    Dim floor$, room$, nr$
    Dim s$
    Dim p&
    Dim d       As Date
    Dim m&
    Dim k&, j&

    Set ws1 = Worksheets("Sheet1")  '現行の一覧表
    Set ws2 = Worksheets("Sheet2")  '交換実績一覧表

    '交換実績一覧表をもとに、”階,エアコン番号"に対応する行indexを辞書に保持
    Set dic = CreateObject("Scripting.Dictionary")
    For k = 2 To ws2.Cells(Rows.Count, "A").End(xlUp).Row
        floor = ws2.Cells(k, "A")
        nr = ws2.Cells(k, "B")
        dic(floor & "," & nr) = k - 1
    Next

    ReDim mat(1 To dic.Count, 1 To 3) As Date

    '現行の一覧表からデータを読み込み、配列matに書き込み
    With ws1
        For k = 3 To .Cells(Rows.Count, "A").End(xlUp).Row
            floor = .Cells(k, "A")
            For j = 2 To 4              '■列範囲調整必要
                room = .Cells(1, j).MergeArea(1)     'セル結合への配慮
                nr = .Cells(2, j)

                If nr <> "" Then
                    s = floor & "," & room & "-" & nr
                Else
                    s = floor & "," & room
                End If

                p = dic(s)      '書き込み先の行index
                d = .Cells(k, j)
                m = Month(d)    '書き込み先の列index(1月〜12月の前提)
                mat(p, m) = d   '配列に保持
            Next
        Next
    End With
    
    '交換実績一覧表に配列を書き込む
    With ws2.[C2].Resize(UBound(mat, 1), UBound(mat, 2))
        .Value = mat
        .NumberFormatLocal = "yyyy/m/d;;;"   '0のときは非表示とするため(改善が必要かも)
    End With
End Sub

考え方を示したものであり、簡単な動作確認はしていますが、
最終的に使えるコードを提供するものではありません。
 
修正が必要な点はあります。適宜修正して下さい。
(例えば、フィルター交換日付が入っているところだけ対象にするとか。)
なお、部屋番号が各階で共通しているのかどうかも不明です。
そのあたりは、説明もないし、そちらで適宜応用してください。

回答
投稿日時: 26/02/11 15:10:32
投稿者: simple

両方の表のデータの出現順序がもし同じであれば、順次処理していくだけでよかったかもしれませんね。
階によっては、エアコンが他の階より少ないといったことでもあって、
上記のような前提がとれないこともあるとすれば、提案したような手法が確実かと思いました。
 
あなたの手法についてコメントします。

引用:
この場合に、各階(配列変数)に紐づいた部屋番号の配列変数、そして、その部屋番号の配列に紐づいた1つ目のエアコンの日付、2つ目のエアコンの日付をセットしていくと、後者の一覧に値を入れていく時に変数から取り出しやすいと思います。

現行の表をもとになんらかのデータ構造を作り、それをもとに「交換実績一覧表」に書き込むとすれば、
dictionaryを入れ子構造にするとよいでしょう。(itemをdictionaryにするわけです)
ただ、扱いが複雑化するので、むしろキーをつなげて単純なdictionaryにする方法(提示済みの方法)
のほうが扱いやすいと思います。
どうしても貴兄の方針が良いというのであれば、dicctionaryの入れ子に挑戦してみて下さい。

回答
投稿日時: 26/02/18 19:51:12
投稿者: simple

回答コメントをしているのですが、なんらかの返事をしていただきたいですね。
 
こちらの記述は読まれているのでしょうか。いや、全然質問内容とちがう話になってます、
ということなら、改めて質問を詳細にしてください。
そうすれば、他の回答者さんからも回答があるものと思います。
 
質問の明確化にあたってお願いしたい点
@
> この場合に、各階(配列変数)に紐づいた部屋番号の配列変数、
> そして、その部屋番号の配列に紐づいた1つ目のエアコンの日付、
> 2つ目のエアコンの日付をセットしていくと、

ここで念頭においているのは、3次元の配列ということですか?
どうしてもそれが希望であれば、その方向で試して、詰まったところを質問して下さい。
 
A
26/02/09 08:39:12 で投稿したとおりの書き方で、データのサンプルを示して下さい。
特に、現在の一覧表で、一行目の横の見出しで各部屋の番号を入れるとありますが、
> なお、部屋番号が各階で共通しているのかどうかも不明です。
> そのあたりは、説明もないし、そちらで適宜応用してください。

ここを明確にしてください。
 
時期も過ぎ、もう興味はありませんというなら、きちんと挨拶して"閉じて"もらえませんか?

トピックに返信