如何使用函数参数作为键从映射中获取值

时间:2019-05-10 20:41:50

标签: elixir

def mapdna(dna) do
  dnarna = %{"G" => "C","C" => "G","T" => "A", "A" => "U"}
  dnarna[dna]
end

当我将“ G”传递给mapdna时,它应该返回“ C”

2 个答案:

答案 0 :(得分:1)

尝试一下:

defmodule My do

  def mapdna(dna) 
  when is_binary(dna) do
    %{"G" => "C","C" => "G","T" => "A", "A" => "U"}[dna]
  end

end

#IO.puts My.mapdna(:G)
IO.puts My.mapdna("G")

在elixir中,要测试参数是否为字符串,请使用is_binary/1

运行代码:

$ elixir my.exs
C

但是,如果我取消注释行:

$ elixir my.exs
** (FunctionClauseError) no function clause matching in My.mapdna/1    

    The following arguments were given to My.mapdna/1:

        # 1
        :G

    my.exs:3: My.mapdna/1
    my.exs:12: (file)
    (elixir) lib/code.ex:677: Code.require_file/2

回复评论:

看看这段代码:

defmodule RNATranscription do 

  @rna_for  %{"G" => "C","C" => "G","T" => "A", "A" => "U"} 

  def to_rna(dna) do  
    String.codepoints(dna)
    |> Enum.map( &(@rna_for[&1]) )
    |> :erlang.list_to_binary
  end 
end

在iex中:

~/elixir_programs$ iex my.ex
Erlang/OTP 20 [erts-9.3] [source] [64-bit] [smp:4:4] [ds:4:4:10] [async-threads:10] [hipe] [kernel-poll:false]
Interactive Elixir (1.6.6) - press Ctrl+C to exit (type h() ENTER for help)

iex(1)> RNATranscription.to_rna "ACGT" 
"UGCA"

iex(2)> 

上面的解决方案对于真正长的DNA字符串不是非常有效(它将字符串拆分为一个列表,然后遍历结果列表以转换值,然后再次遍历该列表以将所有内容连接在一起)。对于长的DNA字符串,可以使用binary pattern matching来获取DNA字符串中的每个字母,并在构建过程中构建RNA字符串。根据{{​​3}},以下解决方案应该是构建RNA字符串的高度优化的方法-即使您要添加RNA字符串的“尾部”:

defmodule RNATranscription do 

  @rna_for  %{"G" => "C","C" => "G","T" => "A", "A" => "U"} 

  def to_rna(dna) do  
    _to_rna(dna, <<>>)  #The second arg will hold the rna string as it's being built
  end 

  defp _to_rna(<<dna_letter::utf8, rest::binary>>, rna_string) do
    rna_letter = @rna_for[<<dna_letter::utf8>>] 
    _to_rna(rest, <<rna_string::binary, rna_letter::binary>>)
  end
  defp _to_rna(<<>>, rna), do: rna 

end

请注意,dna_letter最终是一个代码点(整数),必须使用<<....>>将其转换回二进制(字符串)才能在映射中进行查找。匹配二进制文件时,不能使用以下模式:

<<dna_letter::binary, rest::binary>>

因为::binary类型的默认大小是“您要匹配的二进制文件的其余部分”(尽管您可以显式指定大小)。结果,没有大小的::binary只能在模式中出现一次,并且必须在模式的末尾。 (另一方面,::utf8的默认大小是组成一个utf8代码点的所有字节,最大为4个字节。)

现在,由于您的DNA字母都是ascii字母,即始终为1个字节长,因此您还可以使用以下模式匹配DNA字符串:

<dna_letter::binary-size(1), rest::binary>>

模式中的第一段明确设置了binary类型的大小,因此它将仅匹配一个字节,并且dna_letter最终将成为二进制(字符串),这意味着您不必将代码点转换为字符串以在地图中查找。这是添加到解决方案中的新模式:

defmodule RNATranscription do 

  @rna_for  %{"G" => "C","C" => "G","T" => "A", "A" => "U"} 

  def to_rna(dna) do  
    _to_rna(dna, <<>>)  #The second arg will hold the rna string as it's being built
  end 

  defp _to_rna(<<dna_letter::binary-size(1), rest::binary>>, rna_string) do
    rna_letter = @rna_for[dna_letter] 
    _to_rna(rest, <<rna_string::binary, rna_letter::binary>>)
  end
  defp _to_rna(<<>>, rna), do: rna 

end

我想知道是否行:

_to_rna(rest, <<acc::binary, rna::binary>>)

等效于:

_to_rna(rest, acc <> rna)

??如果是这样,则代码可以使用其他一些长生不老药习惯:

defmodule RNATranscription do 

  @rna_for  %{"G" => "C","C" => "G","T" => "A", "A" => "U"} 

  def to_rna(dna) do  
    _to_rna(dna, "")  #The second arg will hold the rna string as it's being built
  end 

  defp _to_rna(<<dna_letter::binary-size(1)>> <> rest, rna_string) do
    rna_letter = @rna_for[dna_letter]
    _to_rna(rest, rna_string <> rna_letter)
  end
  defp _to_rna("", rna_string), do: rna_string

end

答案 1 :(得分:0)

确定找到了答案

dnarna =%{?G =>?C,?C =>?G,?T =>?A,?A =>?U}