如何在Elixir中循环遍历字符串中的每个字符?

fro*_*age 7 string loops functional-programming elixir

假设我有一个巨大的文本体~500个字符存储在一个字符串中,我怎样才能遍历字符串并在每次遇到字符'a'时将变量增加1?

Pat*_*ity 18

我认为有更容易理解的方法可能对您有用.使用正则表达式:

Regex.scan(~r/a/, str) |> Enum.count
Run Code Online (Sandbox Code Playgroud)

或者将字符串分成unicode字符,然后指望:

str |> String.graphemes |> Enum.count(fn(c) -> c == "a" end)
Run Code Online (Sandbox Code Playgroud)

这些不是非常有效的方法,但性能影响应该可以忽略不计的(相对较小的!)字符串只有500个字符长.

如果您需要更有效的方法,一个好的选择通常是使用递归迭代,然后手动计算出现次数.虽然这种方法非常冗长,但它的表现要好得多.

defmodule Recursive do
  def count(str, <<c::utf8>>) do
    do_count(str, c, 0)
  end

  defp do_count(<<>>, _, acc) do
    acc
  end

  defp do_count(<<c::utf8, rest::binary>>, c, acc) do
    do_count(rest, c, acc + 1)
  end

  defp do_count(<<_::utf8, rest::binary>>, c, acc) do
    do_count(rest, c, acc)
  end
end
Run Code Online (Sandbox Code Playgroud)

最后,这是迄今为止使用这些方法的benchfella的基准.我还包括了@DeboraMartins的"分割长度"解决方案,它在小字符串方面优于上述所有内容.对于较大的字符串,递归方法的差异可以忽略不计.

# 500 Characters

split length         500000   5.90 µs/op
recursive            100000   10.63 µs/op
regex count          100000   24.35 µs/op
graphemes count       10000   118.29 µs/op


# 500.000 Characters

split length            100   11150.59 µs/op
recursive               100   12002.20 µs/op
regex count             100   25313.40 µs/op
graphemes count          10   218846.20 µs/op
Run Code Online (Sandbox Code Playgroud)


小智 9

我的代码消耗是:

countSubstring = fn(_, "") -> 0
                 (str, sub) -> length(String.split(str, sub)) - 1 end
Run Code Online (Sandbox Code Playgroud)

你可以打电话使用 IO.puts countSubstring.(str, "a")