Skip to content

Commit 7ac3a5c

Browse files
committed
dna attempt
1 parent 87b7524 commit 7ac3a5c

1 file changed

Lines changed: 48 additions & 3 deletions

File tree

rounds/3_dna/solution.py

Lines changed: 48 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,58 @@
55
own faster implementation.
66
"""
77

8-
from .baseline import find_matches as _baseline
8+
from mmap import mmap, ACCESS_READ
9+
from concurrent.futures import ThreadPoolExecutor, wait
910

11+
def _subsearch(raw, record_id_start: int, data_start: int, data_end: int, pattern: bytes):
12+
plen = len(pattern)
13+
data = bytes(raw[data_start : data_end - 1]).replace(b"\n", b"")
14+
locations = []
15+
loc = data.find(pattern)
16+
while loc != -1:
17+
locations.append(loc)
18+
loc = data.find(pattern, loc + plen)
19+
20+
if not locations:
21+
return None
22+
23+
record_id = raw[record_id_start : data_start - 1].decode("ascii")
24+
return (record_id, locations)
1025

1126
def find_matches(fasta_path: str, pattern: bytes) -> list[tuple[str, list[int]]]:
1227
"""Find every FASTA record whose sequence contains ``pattern``.
1328
1429
Returns ``[(record_id, [positions...]), ...]`` in file order.
1530
"""
16-
# TODO: remove this delegation and write your own implementation here.
17-
return _baseline(fasta_path, pattern)
31+
source = open(fasta_path, "rb")
32+
data = mmap(source.fileno(), 0, access=ACCESS_READ)
33+
34+
last = -1
35+
36+
data_end = len(data) - 1
37+
while data[data_end] == b"\n":
38+
data_end -= 1
39+
40+
with ThreadPoolExecutor(max_workers=16) as executor:
41+
records = []
42+
while data_end > 0:
43+
gt_pos = data.rfind(b">", 0, data_end)
44+
if gt_pos == -1:
45+
raise Exception("expected greater than")
46+
47+
record_id_start = gt_pos + 1
48+
49+
nl_pos = data.find(b"\n", record_id_start)
50+
if nl_pos == -1:
51+
raise Exception("expected new line")
52+
53+
data_start = nl_pos + 1
54+
55+
records.append(
56+
executor.submit(_subsearch, data, record_id_start, data_start, data_end, pattern)
57+
)
58+
data_end = gt_pos
59+
60+
results = [d.result() for d in records if d.result() is not None]
61+
results.reverse()
62+
return results

0 commit comments

Comments
 (0)