|
@@ -0,0 +1,73 @@
|
|
1
|
+
|
|
2
|
+
|
|
3
|
+from typing import List
|
|
4
|
+from million.model.hole import Hole
|
|
5
|
+from million.model.message import Message
|
|
6
|
+from million.model.sequence import Sequence
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+def compute_sequences(messages: List[Message], accepted_max: int = 1_000_000) -> List[Sequence]:
|
|
10
|
+ sequences: List[Sequence] = []
|
|
11
|
+ current_sequence = Sequence(
|
|
12
|
+ start=messages[0].get_counted_value(),
|
|
13
|
+ start_message=messages[0],
|
|
14
|
+ end=messages[0].get_counted_value(),
|
|
15
|
+ end_message=messages[0]
|
|
16
|
+ )
|
|
17
|
+ for i in range(1, len(messages)):
|
|
18
|
+ message = messages[i]
|
|
19
|
+ message_value = message.get_counted_value()
|
|
20
|
+ if message_value > accepted_max:
|
|
21
|
+ continue
|
|
22
|
+ if message_value - current_sequence.end == 1:
|
|
23
|
+ current_sequence.end = message_value
|
|
24
|
+ current_sequence.end_message = message
|
|
25
|
+ else:
|
|
26
|
+ sequences.append(current_sequence)
|
|
27
|
+ current_sequence = Sequence(
|
|
28
|
+ start=message_value,
|
|
29
|
+ start_message=message,
|
|
30
|
+ end=message_value,
|
|
31
|
+ end_message=message
|
|
32
|
+ )
|
|
33
|
+
|
|
34
|
+ # order the sequences by start
|
|
35
|
+ sequences.sort(key=lambda s: s.start)
|
|
36
|
+
|
|
37
|
+ merged_sequences: List[Sequence] = []
|
|
38
|
+ current_sequence = sequences[0]
|
|
39
|
+ for i in range(1, len(sequences)):
|
|
40
|
+ sequence = sequences[i]
|
|
41
|
+ sequence_start_is_in_current_sequence = current_sequence.start <= sequence.start and current_sequence.end >= sequence.start
|
|
42
|
+ sequence_end_is_further = sequence.end > current_sequence.end
|
|
43
|
+ sequence_start_is_current_end_or_next = sequence.start == current_sequence.end + 1
|
|
44
|
+
|
|
45
|
+ if sequence_start_is_in_current_sequence or sequence_start_is_current_end_or_next:
|
|
46
|
+ if sequence_end_is_further:
|
|
47
|
+ current_sequence.end = sequence.end
|
|
48
|
+ current_sequence.end_message = sequence.end_message
|
|
49
|
+ else:
|
|
50
|
+ merged_sequences.append(current_sequence)
|
|
51
|
+ current_sequence = sequence
|
|
52
|
+
|
|
53
|
+ # Having merged the sequences once, any sequence having start = end can be removed
|
|
54
|
+ return [s for s in merged_sequences if s.start != s.end]
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+def find_holes(messages: List[Message], accepted_max: int = 1_000_000) -> List[Hole]:
|
|
58
|
+ """
|
|
59
|
+ Find the holes in the conversation
|
|
60
|
+ """
|
|
61
|
+ merged_sequences = compute_sequences(messages, accepted_max)
|
|
62
|
+ holes = []
|
|
63
|
+ for i in range(1, len(merged_sequences)):
|
|
64
|
+ previous_sequence = merged_sequences[i - 1]
|
|
65
|
+ sequence = merged_sequences[i]
|
|
66
|
+ if sequence.start - previous_sequence.end > 1:
|
|
67
|
+ holes.append(Hole(
|
|
68
|
+ start=previous_sequence.end,
|
|
69
|
+ end=sequence.start,
|
|
70
|
+ start_message=previous_sequence.end_message,
|
|
71
|
+ end_message=sequence.start_message
|
|
72
|
+ ))
|
|
73
|
+ return holes
|