我正在写一个将RNA转换为DNA的函数。输入以字符列表形式出现:'ATCG'因此我遍历每个字母并使用映射来获取转换后的字母。简单。
问题是枚举字符列表后,我无法将其合并回字符列表。Enum.join返回一个字符串,to_charlist只返回一个字符点列表,我看不到其他任何可以帮助的函数。
这是我的代码:
def to_rna(dna) do
dna_to_rna = %{
'G' => 'C',
'C' => 'G',
'T' => 'A',
'A' => 'U'
}
Enum.map(dna, fn(letter) ->
Map.get(dna_to_rna, [letter])
end)
end
Run Code Online (Sandbox Code Playgroud)
这将输出一个字符列表: ['U', 'G', 'C']。如何将此列表转换为字符列表:'UGC'?
您可以Enum.concat/1在最后使用来加入列表:
Enum.concat(['U', 'A', 'G', 'C']) # => 'UAGC'
Run Code Online (Sandbox Code Playgroud)
def to_rna(dna) do
mapping = %{
'G' => 'C',
'C' => 'G',
'T' => 'A',
'A' => 'U'
}
Enum.reduce(dna, [], fn(letter, acc) ->
acc ++ Map.get(mapping, [letter])
end)
end
Run Code Online (Sandbox Code Playgroud)
这将给出'UAGC'输入值'ATCG'。
不是necropost,但我最近开始学习 Elixir 并且一直在做一些锻炼问题。这个答案可能有点题外话,因为我提出了一个类似的解决方案,而不使用Map.
该Exercism问题的(rna-transcription没有链接)功能输入,如上所述,是一种
charlist
并预期图表分析作为输出。从字符列表文档:
charlist 是一个整数列表,其中所有整数都是有效的代码点。
我们还可以查看 Exercism 提供的
函数 spec , @spec to_rna([char]) :: [char],并看到一个字符列表既是预期的输入也是输出。该内置类型的文件显示,美国charlist()是一样的[char()]。
从问题的描述中,我们看到代码点到代码点的 1:1 映射。地图是一种完全有效的表示方式,但我认为我们可以仅使用迭代和模式匹配来解决问题。
我觉得其他一些答案中遗漏了一个重点:为什么Enum元素用[],例如包裹Enum.map(dna, fn x -> Map.get(%{...}, [x])?这是因为每个迭代元素都是单个字符,即整数/代码点。通过将值包裹在 中[],该代码点将变成一个带有一个字符的图表,例如'C'。该示例的键/值Map都是单元素字符列表。这成功地映射了核苷酸到核苷酸,但它也将元素的类型从整数更改为字符列表。此结果在charlists,而不是一个单一的/平坦charlist,例如列表'GCTA'匝到['C', 'G', 'A', 'U'](charlists的列表),这是不一样的'CGAU'。正如其他解决方案中所指出的,Enum.concat/1以及Enum.flat_map/2是将列表列表变成平面图表的两种方法。从
flat_map文档:
...概念,[
flat_map/2]是类似于的组合map/2和concat/1。
那么,我们可以在没有中间字符列表的情况下执行映射吗?我相信答案是肯定的。与其将每个代码点转换为字符列表,不如直接将代码点转换为预期的代码点?
从上面的文档链接,我们知道代码点只是整数。展示:
iex[1]> Enum.each('CGAU', &IO.inspect/1)
67
71
65
85
:ok
Run Code Online (Sandbox Code Playgroud)
这意味着我们真的只需要将整数/代码点值映射到其他代码点值。但是,当我们尝试映射字符文字时,我觉得映射整数值有点不自然。幸运的是,Elixir 给了我们一个?符号,它代表一个字符文字的整数值(更多在这里),例如
iex> ?G
71
Run Code Online (Sandbox Code Playgroud)
iex[1]> 'ATCG' == [?A, ?T, ?C, ?G]
true
iex[2]> [?A, ?T, ?C, ?G] == [65, 84, 67, 71]
true
Run Code Online (Sandbox Code Playgroud)
使用这个,我们可以直接将单个代码点转换为它们各自的代码点映射,同时仍然使用字符文字,例如
?G -> ?C. 你仍然可以制作Map这些,例如%{?G => ?C, ...}; 但是,我觉得这是模式匹配的好场景。我们可以使用Enum.map带有多个子句的函数。使用这种方法,各个代码点以 1:1 的比例映射,从而产生一个新的扁平化字符列表——允许我们放弃concator flat_map(并节省一些输入)的需要。
@spec to_rna([char]) :: [char]
def to_rna(dna) do
Enum.map(dna, fn
?G -> ?C
?C -> ?G
?T -> ?A
?A -> ?U
end)
end
Run Code Online (Sandbox Code Playgroud)