Egramir的ngram实现

时间:2018-10-19 19:06:27

标签: elixir

我想开发一个很小的脚本,该脚本读取一个句子并在控制台中生成n-gram图形的输出。

这是一个例子

Example
"Show me the code."
Returns
[
  "Show",
  "Show me",
  "Show me the",
  "Show me the code",
  "me",
  "me the",
  "me the code",
  "the",
  "the code",
  "code"
]

这是我的代码:

defmodule M do
  def main do
    sentence = IO.gets("What is the sentence : ")
    ls = String.split(sentence)
    lsSize = length(ls)
    Enum.each 0..lsSize , fn(x) ->
      posNew = x+1
      IO.puts Enum.at(ls,x)
      Enum.each posNew..lsSize , fn(y) ->
        currentWord = Enum.join([Enum.at(ls,x),  Enum.at(ls,y)], " ")
        IO.puts(currentWord)
      end
    end
  end
end

我唯一得到的是:

What is the sentence : one two three
one
one two
one three
one
two
two three
two
three
three

您能帮我吗?我不明白为什么currentCode的值未在Enum.each外部更新并被重置。 我是erlang和Elixir的新手,这就是为什么我无法理解其中的问题。

谢谢!

1 个答案:

答案 0 :(得分:1)

那是因为您一次只连接两个单词。您对Enum.join的调用在这里仅将xy位置的单词连接在一起,而并非全部他们之间的话:

Enum.join([Enum.at(ls,x),  Enum.at(ls,y)], " ")

您需要连接该范围内的所有单词:

Enum.join(Enum.slice(ls, x, y), " ")



此外,您的代码还存在其他一些错误。 在这里,您可以将代码分解为较小的方法,以实现您要执行的操作:

defmodule NGram do
  def run do
    "Enter sentence: "
    |> IO.gets
    |> String.trim
    |> String.split(" ")
    |> build
    |> Enum.map(&IO.puts/1)
    :ok
  end

  def build(words) do
    words
    |> pre_walk
    |> Enum.map(&String.split(&1, " "))
    |> Enum.map(&post_walk/1)
    |> List.flatten
  end

  defp pre_walk(words) do
    length = length(words)

    Enum.map(0..(length-1), fn i ->
      words
      |> Enum.slice(i, length)
      |> Enum.join(" ")
    end)
  end

  defp post_walk(subwords) do
    Enum.map(1..length(subwords), fn i ->
      subwords
      |> Enum.slice(0, i)
      |> Enum.join(" ")
    end)
  end
end