Wil*_*nne 35 enumeration elixir
我正在使用C#构建的一些代码在Elixir中重建一些东西.
这是非常黑客攻击,但完美的工作(虽然不是在Linux上,因此重建).
基本上它做的是检查一些RSS提要并查看是否有任何新内容.这是代码:
Map historic (URL as key, post title as value).
List<string> blogfeeds
while true
for each blog in blogfeeds
List<RssPost> posts = getposts(blog)
for each post in posts
if post.url is not in historic
dothing(post)
historic.add(post)
Run Code Online (Sandbox Code Playgroud)
我想知道如何在Elixir中有效地进行Enumeration.而且,似乎我在"历史性"中添加东西的过程就是反功能编程.
显然,第一步是声明我的URL列表,但除此之外,枚举的想法正在弄乱我的脑袋.有人可以帮帮我吗?谢谢.
Jos*_*lim 87
这是一个很好的挑战,拥有和解决它肯定会让你对函数式编程有所了解.
通常reduce(通常称为fold)函数式语言中的此类问题的解决方案.我将从一个简短的答案(而不是直接翻译)开始,但随时可以要求跟进.
以下方法通常不适用于函数式编程语言:
map = %{}
Enum.each [1, 2, 3], fn x ->
Map.put(map, x, x)
end
map
Run Code Online (Sandbox Code Playgroud)
最后的地图仍然是空的,因为我们不能改变数据结构.每次打电话Map.put(map, x, x),都会返回一张新地图.因此,我们需要在每次枚举后显式检索新映射.
我们可以使用reduce在Elixir中实现这一点:
map = Enum.reduce [1, 2, 3], %{}, fn x, acc ->
Map.put(acc, x, x)
end
Run Code Online (Sandbox Code Playgroud)
Reduce会将前一个函数的结果作为累加器发出,用于下一个项目.运行上面的代码后,变量map将是%{1 => 1, 2 => 2, 3 => 3}.
出于这些原因,我们很少使用each枚举.相反,我们使用的功能的Enum模块,支持广泛的业务,最终回落到reduce时候有没有其他选择.
编辑:回答问题并进行更直接的代码翻译,您可以随时检查和更新地图:
Enum.reduce blogs, %{}, fn blog, history ->
posts = get_posts(blog)
Enum.reduce posts, history, fn post, history ->
if Map.has_key?(history, post.url) do
# Return the history unchanged
history
else
do_thing(post)
Map.put(history, post.url, true)
end
end
end
Run Code Online (Sandbox Code Playgroud)
事实上,这里的集合会更好,所以让我们重构一下并在过程中使用一个集合:
def traverse_blogs(blogs) do
Enum.reduce blogs, HashSet.new, &traverse_blog/2
end
def traverse_blog(blog, history) do
Enum.reduce get_posts(blog), history, &traverse_post/2
end
def traverse_post(post, history) do
if post.url in history do
# Return the history unchanged
history
else
do_thing(post)
HashSet.put(history, post.url)
end
end
Run Code Online (Sandbox Code Playgroud)