Я рассмотрю только суть вашей проблемы, без ссылки на класс DNA
. Должно быть легко реорганизовать то, что следует, довольно легко.
Код
def match_kmers(s1, s2, k)
h1 = dna_to_index(s1, k)
h2 = dna_to_index(s2, k)
h1.flat_map { |k,_| h1[k].product(h2[k] || []) }
end
def dna_to_index(dna, k)
dna.each_char.
with_index.
each_cons(k).
with_object({}) {|arr,h| (h[arr.map(&:first).join] ||= []) << arr.first.last}
end
Примеры
dna1 = 'GCCCAC'
dna2 = 'CCACGC'
match_kmers(dna1, dna2, 2)
#=> [[0, 4], [1, 0], [2, 0], [3, 1], [4, 2]]
match_kmers(dna2, dna1, 2)
#=> [[0, 1], [0, 2], [1, 3], [2, 4], [4, 0]]
match_kmers(dna1, dna2, 3)
#=> [[2, 0], [3, 1]]
match_kmers(dna2, dna1, 3)
#=> [[0, 2], [1, 3]]
match_kmers(dna1, dna2, 4)
#=> [[2, 0]]
match_kmers(dna2, dna1, 4)
#=> [[0, 2]]
match_kmers(dna1, dna2, 5)
#=> []
match_kmers(dna2, dna1, 5)
#=> []
match_kmers(dna1, dna2, 6)
#=> []
match_kmers(dna2, dna1, 6)
#=> []
Объяснение
Рассмотрим dna1 = 'GCCCAC'
. Он содержит 5 2-мер (k = 2
):
dna1.each_char.each_cons(2).to_a.map(&:join)
#=> ["GC", "CC", "CC", "CA", "AC"]
Аналогично для dna2 = 'CCACGC'
:
dna2.each_char.each_cons(2).to_a.map(&:join)
#=> ["CC", "CA", "AC", "CG", "GC"]
Это ключи хэшей, которые dna_to_index
создает дляdna1
и dna2
соответственно. Значения хэша - это массивы индексов, где соответствующий ключ начинается в строке ДНК. Давайте вычислим эти хэши для k = 2
:
h1 = dna_to_index(dna1, 2)
#=> {"GC"=>[0], "CC"=>[1, 2], "CA"=>[3], "AC"=>[4]}
h2 = dna_to_index(dna2, 2)
#=> {"CC"=>[0], "CA"=>[1], "AC"=>[2], "CG"=>[3], "GC"=>[4]}
h1
показывает, что:
"GC"
начинается с индекса 0 dna1
"CC"
начинается с индексов 1 и 2 из dna1
"CA"
начинается с индекса 3 из dna1
"CC"
начинается с индекса 4 из dna1
h2
имеет аналогичную интерпретацию. См. Enumerable # flat_map и Array # product .
Затем метод match_kmers
используется для построения желаемого массива пар индексов [i, j]
, таких, что h1[i] = h2[j]
.
Теперь давайте посмотрим на хэши, созданные для 3-мер (k = 3
):
h1 = dna_to_index(dna1, 3)
#=> {"GCC"=>[0], "CCC"=>[1], "CCA"=>[2], "CAC"=>[3]}
h2 = dna_to_index(dna2, 3)
#=> {"CCA"=>[0], "CAC"=>[1], "ACG"=>[2], "CGC"=>[3]}
Мы видим, что первый 3-элемент в dna1
равен "GCC"
, начиная с индекса 0. Однако этот 3-мер отсутствует в dna2
, поэтому в возвращаемом массиве нет элементов [0, X]
(X
является просто заполнителем). "CCC"
также не является ключом ко второму хешу. "CCA"
и "CAC"
присутствуют во втором хеше, поэтому возвращаемый массив:
h1["CCA"].product(h2["CCA"]) + h1["CAC"].product(h2["CAC"])
#=> [[2, 0]] + [[3, 1]]
#=> [[2, 0], [3, 1]]