-
Notifications
You must be signed in to change notification settings - Fork 5.3k
Expand file tree
/
Copy pathbinary.py
More file actions
108 lines (71 loc) · 2.86 KB
/
binary.py
File metadata and controls
108 lines (71 loc) · 2.86 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
"""
The binary search algorithm.
"""
from typing import Optional, Sequence, Set
from search import Key, S, T, identity
def find_index(
elements: Sequence[T], value: S, key: Key = identity
) -> Optional[int]:
"""Return the index of value in elements or None."""
left, right = 0, len(elements) - 1
while left <= right:
middle = (left + right) // 2
middle_element = key(elements[middle])
if middle_element == value:
return middle
if middle_element < value:
left = middle + 1
elif middle_element > value:
right = middle - 1
return None
def find_leftmost_index(
elements: Sequence[T], value: S, key: Key = identity
) -> Optional[int]:
"""Return the leftmost index of value in elements or None."""
index = find_index(elements, value, key)
if index is not None:
while index >= 0 and key(elements[index]) == value:
index -= 1
index += 1
return index
def find_rightmost_index(
elements: Sequence[T], value: S, key: Key = identity
) -> Optional[int]:
"""Return the rightmost index of value in elements or None."""
index = find_index(elements, value, key)
if index is not None:
while index < len(elements) and key(elements[index]) == value:
index += 1
index -= 1
return index
def find_all_indices(
elements: Sequence[T], value: S, key: Key = identity
) -> Set[int]:
"""Return a set of indices of elements with matching key."""
left = find_leftmost_index(elements, value, key)
right = find_rightmost_index(elements, value, key)
if left and right:
return set(range(left, right + 1))
return set()
def find(elements: Sequence[T], value: S, key: Key = identity) -> Optional[T]:
"""Return an element with matching key or None."""
return _get(elements, find_index(elements, value, key))
def find_leftmost(
elements: Sequence[T], value: S, key: Key = identity
) -> Optional[T]:
"""Return the leftmost element or None."""
return _get(elements, find_leftmost_index(elements, value, key))
def find_rightmost(
elements: Sequence[T], value: S, key: Key = identity
) -> Optional[T]:
"""Return the rightmost element or None."""
return _get(elements, find_rightmost_index(elements, value, key))
def find_all(elements: Sequence[T], value: S, key: Key = identity) -> Set[T]:
"""Return a set of elements with matching key."""
return {elements[i] for i in find_all_indices(elements, value, key)}
def contains(elements: Sequence[T], value: S, key: Key = identity) -> bool:
"""Return True if value is present in elements."""
return find_index(elements, value, key) is not None
def _get(elements: Sequence[T], index: Optional[int]) -> Optional[T]:
"""Return element at the given index or None."""
return None if index is None else elements[index]