-
Notifications
You must be signed in to change notification settings - Fork 312
/
Copy pathutil.py
150 lines (118 loc) · 3.6 KB
/
util.py
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
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
"""
A module for general utility functions
"""
import io
import math
import os
import numpy as np
from typing import List, Sequence, Tuple
def lines_to_file(file_name: str, write_dir: str, lines: Sequence[str]):
"""
Write each line in a list of strings to a text file.
Parameters
----------
file_name: str
The base name of the file
write_dir : str
The output directory in which the file is to be written.
lines : list
The lines to be written to the text file.
Returns
-------
N/A
"""
with open(os.path.join(write_dir, file_name), "w", encoding="utf-8") as f:
for l in lines:
f.write(f"{l}\n")
def is_monotonic(items: Sequence) -> bool:
"""
Determine whether elements in a list are monotonic. ie. unique
elements are clustered together.
ie. [5,5,3,4] is, [5,3,5] is not.
Parameters
----------
items : Sequence
The input elements to be checked.
Returns
-------
bool
Whether the elements are monotonic (True) or not (False).
"""
prev_elements = set({items[0]})
prev_item = items[0]
for item in items:
if item != prev_item:
if item in prev_elements:
return False
prev_item = item
prev_elements.add(item)
return True
def downround(x, base):
"""
Round <x> down to nearest <base>.
Parameters
---------
x : str, int, float
The number that will be rounded down.
base : int, float
The base to be rounded down to.
Returns
-------
float
The rounded down result of <x> down to nearest <base>.
"""
return base * math.floor(float(x) / base)
def upround(x, base):
"""
Round <x> up to nearest <base>.
Parameters
---------
x : str, int, float
The number that will be rounded up.
base : int, float
The base to be rounded up to.
Returns
-------
float
The rounded up result of <x> up to nearest <base>.
"""
return base * math.ceil(float(x) / base)
def overlapping_ranges(
ranges_1: Sequence[Tuple[int, int]],
ranges_2: Sequence[Tuple[int, int]],
) -> List[Tuple[int, int]]:
"""
Given two collections of integer ranges, return a list of ranges
in which both input inputs overlap.
From: https://stackoverflow.com/q/40367461
Slightly modified so that if the end of one range exactly equals
the start of the other range, no overlap would be returned.
"""
return [
(max(first[0], second[0]), min(first[1], second[1]))
for first in ranges_1
for second in ranges_2
if max(first[0], second[0]) < min(first[1], second[1])
]
def fromfile(fileobj, dtype, count=-1):
"""
Detect if the object will work with numpy.fromfile - if so, use it. If not, read the object into a numpy array and
calculate the number of elements (if not provided) - this is needed for fsspec objects.
"""
if isinstance(fileobj, io.FileIO) or (
isinstance(fileobj, (io.BufferedReader, io.BufferedRandom))
and isinstance(fileobj.raw, io.FileIO)
):
return np.fromfile(fileobj, dtype=dtype, count=count)
else:
dtype = np.dtype(dtype)
if count < 0:
start = fileobj.tell()
fileobj.seek(0, os.SEEK_END)
end = fileobj.tell()
fileobj.seek(start, os.SEEK_SET)
count = (end - start) // dtype.itemsize
array = np.empty(count, dtype)
size = fileobj.readinto(array.view(np.uint8))
array.resize(size // dtype.itemsize)
return array