如何在Elixir中按关键字拆分列表

Tho*_*wne 8 elixir

假设我有一个单词列表,其中一个关键字,在这种情况下是"停止",划分完整的句子:

["Hello", "from", "Paris", "stop", "Weather", "is", "sunny", "stop", "Missing", "you", "stop"]
Run Code Online (Sandbox Code Playgroud)

我想变成:

[["Hello", "from", "Paris"], ["Weather", "is", "sunny"], ["Missing", "you"]]
Run Code Online (Sandbox Code Playgroud)

我知道我可以用String.split的字符串做到这一点,但理想情况下我想学习如何用基本的功能结构解决上述问题,比如[head | tail]等的递归,但我无法弄清楚在哪里去开始如何累积中间列表.

AbM*_*AbM 7

你可以使用chunk_by/2:

["Hello", "from", "Paris", "stop", "Weather", "is", "sunny", "stop", "Missing", "you", "stop"]    
|> Enum.chunk_by(fn(x) -> x != "stop" end) 
|> Enum.reject(fn(x) -> x == ["stop"] end)
Run Code Online (Sandbox Code Playgroud)

性能

出于好奇,我想对这个问题的实现性能进行基准测试.基准测试是针对每个实现的100,000次调用,我运行了3次.如果有人有兴趣,以下是结果:

0.292903s | 0.316024s | 0.292106s | chunk_by

0.168113s | 0.152456s | 0.151854s | Main.main(@ Dogbert的回答)

0.167387s | 0.148059s | 0.143763s | chunk_on(@Martin Svalin的回答)

0.177080s | 0.180632s | 0.185636s | 分裂器(@ stephen_m的答案)


Dog*_*ert 3

这是使用模式匹配的简单尾递归实现:

defmodule Main do
  def split_on(list, on) do
    list
    |> Enum.reverse
    |> do_split_on(on, [[]])
    |> Enum.reject(fn list -> list == [] end)
  end

  def do_split_on([], _, acc), do: acc
  def do_split_on([h | t], h, acc), do: do_split_on(t, h, [[] | acc])
  def do_split_on([h | t], on, [h2 | t2]), do: do_split_on(t, on, [[h | h2] | t2])

  def main do
    ["Hello", "from", "Paris", "stop", "Weather", "is", "sunny", "stop", "Missing", "you", "stop"]
    |> split_on("stop")
    |> IO.inspect
  end
end

Main.main
Run Code Online (Sandbox Code Playgroud)

输出:

[["Hello", "from", "Paris"], ["Weather", "is", "sunny"], ["Missing", "you"]]
Run Code Online (Sandbox Code Playgroud)