我正在编写一个将 RNA 转换为 DNA 的函数。输入以char列表形式出现:'ATCG'
所以我遍历每个字母并使用地图来获取转换后的字母。简单。
问题是在枚举字符列表后我无法将其合并回char列表。 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
这会输出一个字符列表:['U', 'G', 'C']
。如何将此列表转换为charlist:'UGC'
?
答案 0 :(得分:5)
您最后可以使用Enum.concat/1
加入列表:
Enum.concat(['U', 'A', 'G', 'C']) # => 'UAGC'
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
这将为输入值'UAGC'
提供'ATCG'
。
答案 1 :(得分:4)
不是 necropost,但我最近开始学习 Elixir 并且一直在做一些锻炼问题。
这个答案可能有点偏离主题,因为我提出了一个类似的解决方案, 不使用 Map
。
如上所述,Exercism 问题的 (rna-transcription
, no link) 函数输入是一个
charlist
并期望图表师作为输出。
来自字符列表文档:
字符列表是一个整数列表,其中所有整数都是有效的代码点。
我们还可以查看 Exercism 提供的
function spec、@spec to_rna([char]) :: [char]
和看到一个字符列表是预期的输入和输出。
built-in types documentation 向我们显示 charlist()
与 [char()]
相同。
从问题的描述中,我们看到代码点到代码点的 1:1 映射。地图是一种完全有效的表示方式,但我认为我们可以仅使用迭代和模式匹配来解决问题。
我觉得其他一些答案中遗漏了一个重点:为什么 Enum
元素用 []
包裹,例如Enum.map(dna, fn x -> Map.get(%{...}, [x])
?
这是因为每个迭代元素都是单个字符,即整数/代码点。通过将值包装在 []
中,该代码点被转换为具有一个字符的图表,例如'C'
。示例 Map
的键/值都是单元素字符列表。这成功地映射了核苷酸到核苷酸,但它也将元素的类型从整数更改为字符列表。
这会产生一个字符列表,而不是单个/平面字符列表,例如'GCTA'
变成 ['C', 'G', 'A', 'U']
(字符列表),不与 'CGAU'
相同。
正如其他解决方案中所指出的,Enum.concat/1
和 Enum.flat_map/2
都是将列表列表变成平面图表的方法。来自
flat_map
docs:
... 从概念上讲,[flat_map/2
] 类似于 map/2
和 concat/1
的组合。
那么,我们可以在没有中间字符列表的情况下执行映射吗?我相信答案是肯定的。 与其将每个代码点转换为字符列表,不如直接将代码点转换为预期的代码点?
从上面的文档链接,我们知道代码点只是整数。演示:
iex[1]> Enum.each('CGAU', &IO.inspect/1)
67
71
65
85
:ok
这意味着我们真的只需要将整数/代码点值映射到其他代码点值。
但是,当我们尝试映射字符文字时,我觉得映射整数值有点不自然。
幸运的是,Elixir 为我们提供了 ?
符号,它表示字符字面量 (more here) 的整数值,例如
iex> ?G
71
iex[1]> 'ATCG' == [?A, ?T, ?C, ?G]
true
iex[2]> [?A, ?T, ?C, ?G] == [65, 84, 67, 71]
true
使用这个,我们可以直接将单个代码点转换为它们各自的代码点映射,同时仍然使用字符文字,例如
?G -> ?C
。您仍然可以制作其中的 Map
,例如%{?G => ?C, ...}
;但是,我觉得这是模式匹配的好场景。
我们可以将 Enum.map
与具有多个子句的函数一起使用。
使用这种方法,单个代码点被 1:1 映射,从而产生一个新的平面字符列表——允许我们放弃 concat
或 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
答案 2 :(得分:0)
您可以使用Enum.map和Enum.concat来解决它:
def to_rna(dna) do
dna
|> Enum.map(fn x -> Map.get(%{'G' => 'C', 'C' => 'G', 'T' => 'A', 'A' => 'U'}, [x]) end)
|> Enum.concat()
end
答案 3 :(得分:-1)
:lists.flatten(['A', 'B','C'])
这是列表模块中的erlang函数。在elixir中,您可以将erlang函数调用为:。