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

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

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

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

Q&A

解決済

2回答

1195閲覧

Python 時刻を比較して一部の時間をくり抜く

begginer_pygo

総合スコア16

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

0グッド

0クリップ

投稿2021/08/23 07:46

Python初心者にお教えください

以下のような時刻のデータがあったときに、Aの時刻からBの時刻をくり抜いた結果Cが欲しいです。

         開始        終了 A =[2021/08/23 12:00:00,2021/08/23 18:00:00] B =[2021/08/23 13:00:00,2021/08/23 14:00:00] C =[(2021/08/23 12:00:00,2021/08/23 13:00:00),(2021/08/23 14:00:00,2021/08/23 18:00:00)]

またBの時刻が複数あったときやAの終了をBの終了が上回るときは,以下のような結果が欲しいです

         開始        終了 A =[2021/08/23 12:00:00,2021/08/23 18:00:00] B =[(2021/08/23 13:00:00,2021/08/23 14:00:00),(2021/08/23 17:00:00,2021/08/23 21:00:00)] C =[(2021/08/23 12:00:00,2021/08/23 13:00:00),(2021/08/23 14:00:00,2021/08/23 17:00:00)]

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

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

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

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

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

Ftps

2021/08/23 07:53

くり抜くというのは、そのデータの一部を持ってくるということでしょうか?また、Cの順番を教えて下さい(開始、終了など)
otn

2021/08/23 08:12

A[0],A[1],B[0],B[1]の大小を比較して場合分けすれば良いと思いますが、 if文を知らないと言うことなのでしょうか?あるいは大小比較のやり方が分からない?
udon-ken

2021/08/23 09:47

> 以下のような時刻のデータがあったときに そもそも、それが代入式であるとしたらエラーになって代入もできないです。 単純にやるとしたら""を付けて文字列にするくらいですが、それだと単なる文字列です。 時刻としてなんらかの処理をするなら、まず時刻としてデータを整える必要があります。 つまり、そのような時刻データがありえませんので質問が成り立っていません。
guest

回答2

0

ベストアンサー

A も B も複数の範囲を指定できるようにしたので、
1つの場合でも ( ) をつけて tuple にしないといけません。
というのが最初のコードでしたが、その問題を修正しました。

Python

1def range_sub(a, b): 2 if len(a) == 0 or len(b) == 0: return [] 3 if type(a[0]) != tuple: a = [tuple(a)] 4 if type(b[0]) != tuple: b = [tuple(b)] 5 c = [] 6 for t in a: 7 c.append([t[0], 2]) 8 c.append([t[1], 3]) 9 for t in b: 10 c.append([t[0], 1]) 11 c.append([t[1], 4]) 12 c.sort(); 13 aa = bb = False 14 d = [] 15 for t in c: 16 if t[1] == 2: 17 if not aa and not bb: d.append(t[0]) 18 aa = True 19 elif t[1] == 3: 20 if aa and not bb: d.append(t[0]) 21 aa = False 22 elif t[1] == 1: 23 if not bb and aa: d.append(t[0]) 24 bb = True 25 else: 26 if bb and aa: d.append(t[0]) 27 bb = False 28 c = [] 29 for i in range(0, len(d), 2): 30 c.append((d[i], d[i+1])) 31 if len(c) == 1: c = [c[0][0], c[0][1]] 32 return c 33 34 35a = ["2021/08/23 12:00:00", "2021/08/23 18:00:00"] 36b = ["2021/08/23 13:00:00", "2021/08/23 14:00:00"] 37c = range_sub(a, b) 38print(a) 39print(b) 40print(c) 41print() 42 43a = ["2021/08/23 12:00:00", "2021/08/23 18:00:00"] 44b = [("2021/08/23 13:00:00", "2021/08/23 14:00:00"), ("2021/08/23 17:00:00", "2021/08/23 21:00:00")] 45c = range_sub(a, b) 46print(a) 47print(b) 48print(c) 49print() 50 51a = ["2021/08/23 12:00:00", "2021/08/23 18:00:00"] 52b = ["2021/08/23 19:00:00", "2021/08/23 20:00:00"] 53c = range_sub(a, b) 54print(a) 55print(b) 56print(c) 57

わからないことがあれば、コメントをください。

投稿2021/08/23 10:27

編集2021/08/24 03:28
kazuma-s

総合スコア8224

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

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

0

Subtract Overlaps Between Two Ranges Without Setsが参考になりそうです。
こういった問題はSegment treeを使うとよいようです。

以下は上記の[回答コード]((https://stackoverflow.com/a/6462731)を修正して試してみた例です。
正直アルゴリズムは理解できていませんが、質問例ではうまく計算できました。
なお、実際の利用には日時のデータを整数値に変換してください(難しくはありません)。

参考:セグメント木を徹底解説!0から遅延評価やモノイドまで

Python

1from functools import reduce 2 3# Subtract Overlaps Between Two Ranges Without Sets 4# https://stackoverflow.com/questions/6462272/subtract-overlaps-between-two-ranges-without-sets 5# https://stackoverflow.com/a/6462731 6class IntervalTree: 7 def __init__(self, h, left, right): 8 self.h = h 9 self.left = left 10 self.right = right 11 12def merge(A, B, op, l=-float("inf"), u=float("inf")): 13 if l > u: 14 return None 15 if not isinstance(A, IntervalTree): 16 if isinstance(B, IntervalTree): 17 opT = op 18 A, B, op = B, A, (lambda x, y : opT(y,x)) 19 else: 20 return op(A, B) 21 left = merge(A.left, B, op, l, min(A.h, u)) 22 right = merge(A.right, B, op, max(A.h, l), u) 23 if left is None: 24 return right 25 elif right is None or left == right: 26 return left 27 return IntervalTree(A.h, left, right) 28 29def to_range_list(T, l=-float("inf"), u=float("inf")): 30 if isinstance(T, IntervalTree): 31 return to_range_list(T.left, l, T.h) + to_range_list(T.right, T.h, u) 32 #return [(l, u-1)] if T else [] # - 33 return [(l, u)] if T else [] # + 34 35def range_list_to_tree(L): 36 return reduce(lambda x, y : merge(x, y, lambda a, b: a or b), 37 #[ IntervalTree(R[0], False, IntervalTree(R[1]+1, True, False)) for R in L ]) # - 38 [ IntervalTree(R[0], False, IntervalTree(R[1], True, False)) for R in L ]) # + 39 40# helper function 41def get_interval_list( A, B): 42 r1 = range_list_to_tree(A) 43 r2 = range_list_to_tree(B) 44 diff = merge(r1, r2, lambda a, b : a and not b) 45 return to_range_list(diff) 46 47A =[(12, 18)] 48B =[(13, 14)] 49ret = get_interval_list( A, B) 50print(ret) # [(12, 13), (14, 18)] 51 52A = [(12, 18)] 53B = [(13, 14), (17, 21)] 54ret = get_interval_list( A, B) 55print(ret) # [(12, 13), (14, 17)]

投稿2021/08/23 09:11

can110

総合スコア38339

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

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.37%

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

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

質問する

関連した質問