こんにちはゲストさん。会員登録(無料)して質問・回答してみよう!

締切り済みの質問

複数時間情報の重複を求める

プログラミングの考え方に関する質問です。
例:
施設Aを、ユーザーaaa が11:00から15:00まで4時間使った。
施設Aを、ユーザーbbb が12:00から14:00まで2時間使った。
施設Aを、ユーザーccc が13:00から16:00まで3時間使った。

開始時間、終了時間、人数のパラメータが変数であるとして、
複数ユーザーで「施設Aを共用」していた時間を各ユーザーで調べたいと思います。
この例では[共用]時間は下記のようになります。
aaaは 12:00-15:00の3時間
bbbは 12:00-14:00の2時間
cccは 13:00-15:00の2時間

重複する時間の検出方法として、どのような方法がよいでしょうか。

投稿日時 - 2011-09-27 19:50:05

QNo.7038088

困ってます

このQ&Aは役に立ちましたか?

0人が「このQ&Aが役に立った」と投票しています

回答(8)

ANo.8

No6に大事なルーティーンが抜けていたので
少しお待ちを。

投稿日時 - 2011-10-05 11:19:53

ANo.7

No6です。

もし、同じ人物が複数回出入りする場合は、
データを、

利用番号  氏名  入室時刻     退室時刻
1     aaa   2011/1/1 11:00 2011/1/1 17:00
2     bbb   2011/1/1 13:00 2011/1/1 15:00
3     ccc   2011/1/1 14:00 2011/1/1 15:30
4     ddd   2011/1/1 17:00 2011/1/1 19:00
5     eee   2011/1/1 9:00  2011/1/1 11:00
6     bbb   2011/1/1 16:30 2011/1/1 17:30
7     ccc   2011/1/1 16:50 2011/1/1 18:20

のように、利用番号フィールドを設定し、利用番号での
時刻検索をすれば氏名が複数出てくる上記の例でも、
ほぼそのままNo6のコードが流用できます。
プロシージャの引数は利用番号に変更します。

あるいは、プロシージャの中ですべての利用番号を
検索処理するかでしょう。その場合は、No6の
プロシージャに、もう一つ上から利用番号を順次
抽出していくFor~Nextのループをかぶせる
必要があります。

やりかたはいろいろです。

投稿日時 - 2011-10-04 19:01:23

ANo.6

Sheet1に以下のようにデータが入っているとします。

氏名  入室時刻     退室時刻
aaa   2011/1/1 11:00 2011/1/1 17:00
bbb   2011/1/1 13:00 2011/1/1 15:00
ccc   2011/1/1 14:00 2011/1/1 15:30
ddd   2011/1/1 17:00 2011/1/1 19:00
eee   2011/1/1 9:00  2011/1/1 11:00

一応、Subプロシージャに名前を渡せば、メッセージボックスで
時刻が表示されます。連続して名前を取り出す場合は、フラッグの
設定等に注意をする必要があります。
共用時間帯での人数、氏名は、ループ中の中で簡単に取り出せます。
中に一部コメントアウトしたものが残っていたりするものがあるか
もしれません。ご容赦。たぶん、まともに動くとは思いますが。
何かあれば、補足してください。

プロシージャを関数に渡して、名前をループしてもいいかも
しれません。あとは、応用してください。


Sub test1(strName As String)
Dim ws As Worksheet
Dim dIn As Date '開始日
Dim dOut As Date '終了日
Dim predStart As Date '一時保管用
Dim predEnd As Date '一時保管用
Dim dStart As Date '共用開始日
Dim dEnd As Date '共用終了日
Dim boolStart As Boolean '共用開始フラッグ
Dim boolStartX As Boolean '特異点用共用開始フラッグ
Dim i1 As Long
Dim i2 As Long
Dim i3 As Long
Dim i4 As Long
Dim i5 As Long
Dim k As Long

boolStart = False
boolStartX = False
Set ws = ThisWorkbook.Sheets("Sheet1")
k = ws.Cells(Rows.Count, 1).End(xlUp).Row '最終行

For i1 = 2 To k
'### 対象の検索
If ws.Cells(i1, 1).Value = strName Then
'対象の入室時刻、退室時刻の取得
dIn = ws.Cells(i1, 2).Value
dOut = ws.Cells(i1, 3).Value

'### 共用開始時刻の検索1
For i2 = 2 To k
If ws.Cells(i2, 1).Value <> strName Then
If ws.Cells(i2, 2).Value <= dIn And ws.Cells(i2, 3).Value >= dIn Then
predStart = dIn
dStart = predStart
boolStart = True
ElseIf ws.Cells(i2, 2).Value >= dIn And ws.Cells(i2, 3).Value <= dOut Then
predStart = ws.Cells(i2, 2).Value
If predStart < dStart Then
dStart = predStart
boolStart = True
End If
End If
End If
Next i2

'### 共用開始時刻の検索2
'### 入室時一人で退室時刻と他の人の入室時刻が重なった場合の共用開始時刻
For i3 = 2 To k
If ws.Cells(i3, 1).Value <> strName Then
If boolStart = False Then

If ws.Cells(i3, 2).Value = dOut And ws.Cells(i3, 2).Value > dIn Then
dStart = dOut
boolStartX = True
End If
End If

End If
Next i3

'### 共用終了時刻検索
If boolStart = True Then
For i4 = 2 To k
If ws.Cells(i4, 1).Value <> strName Then
If ws.Cells(i4, 2).Value <= dOut And ws.Cells(i4, 3).Value >= dOut Then
dEnd = dOut
'Exit for
ElseIf ws.Cells(i4, 3).Value >= dIn And ws.Cells(i4, 3).Value <= dOut Then
predEnd = ws.Cells(i4, 3).Value
If predEnd > dEnd Then
dEnd = predEnd
'Exit For
End If
ElseIf ws.Cells(i4, 2).Value >= dOut And ws.Cells(i4, 2).Value < dOut Then
predEnd = ws.Cells(i4, 2).Value
If predEnd > dEnd Then
dEnd = predEnd
End If
End If
End If

Next i4
End If

'### 入室時一人で退室時刻と他の人の入室時刻が重なった場合の共用終了時刻
If boolStartX = True Then
For i5 = 2 To k
If ws.Cells(i5, 1).Value <> strName Then
If ws.Cells(i5, 2).Value = dOut And ws.Cells(i5, 2).Value > dIn Then
dEnd = dOut
'Exit For
End If
End If
Next i5
End If
'Exit For

End If
Next i1

If boolStart = True Then
MsgBox strName & "の共用開始日は" & dStart & Chr(13) & "共用終了日は" & dEnd
End If
If boolStartX = True Then
MsgBox strName & "の共用開始日は" & dStart & Chr(13) & "共用終了日は" & dEnd
End If
Set ws = Nothing
End Sub

投稿日時 - 2011-10-04 16:02:44

お礼

ありがとうございます。
戴いたサンプルを読み解いて、参考にさせていただきます。
質問があるかもしれないので、もう少しの間この件をオープンにさせていただきたいと思います。

投稿日時 - 2011-10-04 18:19:42

ANo.5

__時間帯→
aa□■■■■□□□■■
bb■■□□□■■□□□
cc■□□□□■■□■■
dd□□■■□□□□■■

もう一つ力技で行う方法。
上記を二次元配列に入れてあげて、For ~ Next の二重ループで
配列の値を判定して、それを別の変数にでも格納すれば
各人ごとに誰が同室だったかその時間帯は?までも求められそうですね。

時間帯の区切りは開始時刻からの経過時間を分単位で求めて
区切り時間単位(例 15分とか)で割った商と余りから出せば良さそう。

投稿日時 - 2011-09-29 23:32:41

お礼

回答ありがとうございます。参考になります。

投稿日時 - 2011-10-04 12:51:22

ANo.4

   8 9 10 11 12 1 2 3 4 5 6 7 8
aaa       ・・・・・・・・・・
bbb          ・・・・
ccc            ・・・
ddd                ・・・・
eee   ・・・・・

一つの例として上記のように退室と入室は一回とします。
表が崩れているかもしれませんが、aaaの入室時刻と
eeeの退室時刻はおなじです。また、aaaの退室時刻と
dddの入室時刻は同じです。上記は一つの例です。

入室時刻が、他の人の入室時刻と退室時刻の間に入っている
ならばそれが共用の始まりの時刻となります。もし、
入室したときにだれもいなくて後から誰かが入室すれば、
そのときに入室した人の入室時刻が自分の共用の
始まりの時刻となります。これを自分以外のすべての
人について検索し、その中で一番最初の時刻を共用の
始まりの時刻とします。
上記の例のaaaの入室時刻とeeeの退室時刻が重なりますが、
これを共用時刻と判定するならば、eeeの共用の始まり時刻
は他の場合と別に判定するルーティーンが必要になります。
これらの共用始まりの時刻を検出したならば、フラッグを
立て、共用時刻の終わりの判定に利用します。別途判定する
場合にも別フラッグを立てます。

共用の終わりの時刻の判定は上記の場合と似たようなものです。

共用の始まりと終わりの時刻を検出したら、フラッグ別に
共用の始まりと終わりの時刻を出します。

一人の人物が入室、退室が複数回ある場合もほぼ同様の
処理でできますが、その場合、共用の始まりと終わりの
セットが複数でる可能性があるので、このデータを
どのようにファイルに格納するか考える必要はあります。

プログラムは、ループ処理の入れ子を行なうようになります。

>プログラミングの考え方に関する質問です。

ということなので、コードは載せませんが、必要ならば
載せます。
VB系(Excel、Access、Visual Basic)、あるいはC言語系
でもコードの流れは似たようなものです。

質問のようなプログラムは実際には結構いろいろな
場面で使われています。

投稿日時 - 2011-09-29 14:50:57

お礼

ありがとうございます。私のスキルから現実的なのかという点から考えようと思い、皆様の考え方を参考にさせていただきました。Proin654様の回答が、私の考えから漏れていた部分まで書いていただいており、大変素晴らしいと思いました。
今までは人手で時間を出していたのですがVB系(Excel)に移そうとしています。
もしよろしければ、サンプルをお見せいただけますか?
Excelマクロになっていなくても、VB系コードからExcelへの移植はなんとかできると思います。

投稿日時 - 2011-10-04 13:01:28

ANo.3

2人のユーザの各々1区間のみ取り出した時の
比較は、

シューティングゲームの当たり判定のように、
単純な不等号の判定を組み合わせてもできる
でしょうし、

・4点を昇順に並べて、
考えられるパターンは
aaa aaa bbb bbb × 重なり無し
aaa bbb aaa bbb ○ bbb~aaa
aaa bbb bbb aaa ○ bbb~bbb
bbb aaa bbb aaa ○ aaa~bbb
bbb bbb aaa aaa × 重なり無し
bbb aaa aaa bbb ○ aaa~aaa
・1点目と2点目が同じユーザなら重複なし
・ユーザが変わった点(2点目)から次の点(3点目)まで
に限定できる気がします。そういったまとめ方を
考え出してもいいでしょう。
境界がぴったり一致した時(重なりの長さ0)だけ
除外した方がいいのかな。
# その場の思いつきなのでパターン抜けあったら指摘下さい。

中学生の数学レベルの知識があれば実現する方法は幾つか
ありそうですね。円や図形の範囲が重なってる話なら
高校数学の方程式あたりの出番だけど、そこまで必要
無さそうです。

投稿日時 - 2011-09-28 16:15:43

お礼

回答ありがとうございます。参考になります。

投稿日時 - 2011-10-04 12:51:30

ANo.2

__時間帯→
aa□■■■■□□□■■
bb■■□□□■■□□□
cc■□□□□■■□■■
dd□□■■□□□□■■
こんな風に□は未使用、■は使用中だとして
□→0、■→1と置き換えて
aa0,1,1,1,1,0,0,0,1,1
bb1,1,0,0,0,1,1,0,0,0
cc1,0,0,0,0,1,1,0,1,1
dd0,0,1,1,0,0,0,0,1,1

aaさんが使用中に共有していた時間を求める場合には
aaさん以外の人の時間帯の論理和を求めて
bb1,1,0,0,0,1,1,0,0,0
cc1,0,0,0,0,1,1,0,1,1
dd0,0,1,1,0,0,0,0,1,1
XX1,1,1,1,0,1,1,0,1,1
このXXとaaとを今度は、論理積で
aa□■■■■□□□■■
XX■■■■□■■□■■

AA□■■■□□□□■■
ということかな?(等幅フォントで見てね)
VBA なら Or、And 演算子に説明があります。ウェブ上なら『論理和、論理積』で検索を。
嫌いじゃないけど得意でもないので退散退散。

投稿日時 - 2011-09-28 09:42:38

ANo.1

質問説明が十分でないのでは。補足しておいたほうが良いのでは。
A施設についてB,C・・施設もあり、施設ごとに考えるのでしょうね。
ダブリは1日単位で考えるのか。当然日付の要素は必要で(日が違えば同じ時間帯でも該当しないだろう)データ上どうなっているのか。
利用時間はスタートとエンドとも何時単位で良いか(3/・45分に終るとか9/15にはじめるなどがあるのか。
例示データが不足ないしは実態の説明不足だろう。
ーー
珍しいいタイプで、相当手ごわいような気もする。このアルゴリズムは、数学や論理が得意な人の読む、質問コーナーに投稿するのが良いのでは。
ーー
>人数のパラメータが
突然出てきているが、これはどういうこと?
ーー
時間帯別重複人数ではなく、利用者別に重複時間を出すのか?

投稿日時 - 2011-09-27 22:10:59

お礼

質問内容をご理解いただけなくて残念です。
次回から気をつけます。
ありがとうございました。

投稿日時 - 2011-10-04 12:53:22

あなたにオススメの質問