-
Notifications
You must be signed in to change notification settings - Fork 0
/
hairpins.exs
99 lines (82 loc) · 2.74 KB
/
hairpins.exs
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
require Integer
defmodule HairpinSequence do
@moduledoc """
A collection of functions for working with
hairpin nucleotide sequences
"""
@complements %{
"G" => "C",
"C" => "G",
"A" => "T",
"T" => "A"
}
@doc """
Determines the length of an input hairpin sequence
"""
@spec get_hairpin_length!(String.t()) :: number()
def get_hairpin_length!(nucleotide_sequence) do
sequence_length = String.length(nucleotide_sequence)
cond do
_is_even_length_non_hp?(nucleotide_sequence, sequence_length) == true ->
raise ArgumentError, message: "Even length non-hp"
_first_last_bases_non_complementary?(nucleotide_sequence) == true ->
raise ArgumentError, message: "First and last bases are non-complementary"
true ->
_hp_len(nucleotide_sequence, sequence_length)
end
end
@spec _hp_len(String.t(), number()) :: number()
defp _hp_len(nucleotide_sequence, sequence_length) do
indexes = Enum.to_list(0..(div(sequence_length, 2) - 1))
checks =
Enum.map(
indexes,
fn x ->
_are_complements?(
String.at(nucleotide_sequence, x),
String.at(nucleotide_sequence, sequence_length - x - 1)
)
end
)
matched_complements =
Enum.filter(
Enum.to_list(0..(length(checks) - 2)),
fn x ->
(Enum.at(checks, x) and Enum.at(checks, x + 1)) == true
end
)
cond do
length(matched_complements) == 0 ->
1
length(matched_complements) > 0 ->
length(matched_complements) + 1
end
end
@spec _first_last_bases_non_complementary?(String.t()) :: boolean()
defp _first_last_bases_non_complementary?(nucleotide_sequence) do
first_base = String.first(nucleotide_sequence)
last_base = String.last(nucleotide_sequence)
cond do
_are_complements?(first_base, last_base) == false ->
true
_are_complements?(first_base, last_base) == true ->
false
end
end
@spec _is_even_length_non_hp?(String.t(), number()) :: boolean()
defp _is_even_length_non_hp?(nucleotide_sequence, sequence_length) do
is_even_length = Integer.is_even(sequence_length)
leftmost_middle_base = String.at(nucleotide_sequence, div(sequence_length, 2) - 1)
rightmost_middle_base = String.at(nucleotide_sequence, div(sequence_length, 2))
cond do
is_even_length and _are_complements?(leftmost_middle_base, rightmost_middle_base) == true ->
true
is_even_length and _are_complements?(leftmost_middle_base, rightmost_middle_base) == false ->
false
end
end
@spec _are_complements?(String.t(), String.t()) :: boolean()
defp _are_complements?(base_one, base_two) do
@complements[base_one] == base_two
end
end