2016-04-03 55 views
4

说我有一个巨大的文本〜500个字符存储在一个字符串中,我怎么能通过字符串循环,每次我遇到字符'a'时增加一个变量1?如何循环访问Elixir中的每个字符?

+6

欢迎来到Stack Overflow!你是否试图自己解决这个问题?如果是这样,你究竟在哪里卡住?总的来说,人们对“请为我制作这些代码” - 请求(看起来像这样)做出的反应不是很好,但是**做得很好**“我试过这个,现在我被卡住了,请帮助“ - 请求;-) – Carpetsmoker

+1

500个字符很小,不是很大。在500个字符处,很难找到检查字符串的不好方法。 –

回答

7

我的代码sugestion是:

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

你可以叫使用IO.puts countSubstring.(str, "a")

+1

这很好,你能解释一下这是如何工作的吗?我不明白它是如何跟踪参数中每个“”的计数。对不起,我不习惯Elixir这是我的第一个项目,语法对我来说不是很友好:S – frostmage

+0

虽然它不是最直观的解决方案,但它表现非常出色,同时也处理多个字符。在我的答案中看到基准。 –

+0

查看https://learnxinyminutes.com/docs/elixir/以快速查看涉及匿名函数的语法。简而言之,Elixir函数(包括匿名函数)可以定义多个签名,被调用的版本基于模式匹配和/或门。第一个变体处理输入子字符串为空的情况。第二个处理其他用例 - String.split()返回一个列表,该列表的大小减1对应于子字符串的出现次数。希望有所帮助。 – Everett

12

我认为有更容易理解的方法来这,可能只是罚款你。使用正则表达式:

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 
相关问题