【问题标题】:How can I loop through each character in a string in Elixir? [closed]如何循环遍历 Elixir 中字符串中的每个字符? [关闭]
【发布时间】:2016-04-03 17:22:43
【问题描述】:

假设我在一个字符串中存储了大约 500 个字符的大量文本,我如何遍历字符串并在每次遇到字符“a”时将变量加 1?

【问题讨论】:

  • 欢迎来到 Stack Overflow!您是否已经尝试自己解决此问题?如果是这样,你到底是在哪里卡住的?我一般来说,人们对“请为我编写此代码”的请求(看起来像)的反应不太好,但确实对“我试过了,现在我被卡住了”的反应很好/困惑,请帮助”-请求 ;-)
  • 500 个字符很小,不是很大。 500 个字符,很难找到检查字符串的坏方法。

标签: string loops functional-programming elixir


【解决方案1】:

我认为有一些更容易理解的方法可能适合您。使用正则表达式:

Regex.scan(~r/a/, str) |> Enum.count

或将字符串分成其 unicode 字符,然后依靠它:

str |> String.graphemes |> Enum.count(fn(c) -> c == "a" end)

这些不是非常有效的方法,但是对于只有 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

最后,这是一个使用 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

【讨论】:

    【解决方案2】:

    我对代码的建议是:

    countSubstring = fn(_, "") -> 0
                     (str, sub) -> length(String.split(str, sub)) - 1 end
    

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

    【讨论】:

    • 这很好,你能解释一下它是如何工作的吗?我不明白它如何跟踪参数中每个“”的计数。抱歉,我不习惯 Elixir,这是我的第一个项目,语法对我不太友好:S
    • 虽然不是最直观的解决方案,但它的性能非常好,而且还能处理多个字符。请参阅我的答案中的基准。
    • 查看learnxinyminutes.com/docs/elixir 以快速了解涉及匿名函数的语法。简而言之,Elixir 函数(包括匿名函数)可以定义多个签名,并且被调用的版本基于模式匹配和/或门。第一个变体处理输入子字符串为空的情况。第二个处理其他用例—— String.split() 返回一个列表,该列表的大小减 1 对应于子字符串的出现。希望对您有所帮助。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-01-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-01-11
    相关资源
    最近更新 更多