Elixir-遍历并添加到地图 [英] Elixir - Looping through and adding to map

查看:73
本文介绍了Elixir-遍历并添加到地图的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在用我在C#中构建的某些代码在Elixir中重建某些东西。

I'm rebuilding something in Elixir from some code I built in C#.

它虽然被黑了,但是运行良好(尽管不是在Linux上,所以可以重建) )。

It was pretty hacked together, but works perfectly (although not on Linux, hence rebuild).

基本上,它所做的是检查一些RSS提要,看是否有任何新内容。这是代码:

Essentially what it did was check some RSS feeds and see if there was any new content. This is the code:

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)

我想知道如何在Elixir中有效地进行枚举。另外,似乎我向历史记录添加内容的过程就是反功能编程。

I am wondering how I can do Enumeration effectively in Elixir. Also, it seems that my very process of adding things to "historic" is anti-functional programming.

显然,第一步是声明我的URL列表,但除此之外枚举的想法弄乱了我的头脑。有人可以帮我吗?谢谢。

Obviously the first step was declaring my list of URLs, but beyond that the enumeration idea is messing with my head. Could someone help me out? Thanks.

推荐答案

这是一个很好的挑战,解决它肯定会让您对函数式编程有所了解。

This is a nice challenge to have and solving it will definitely give you some insight into functional programming.

使用功能语言解决此类问题的方法通常是 reduce (通常称为 fold )。我将从一个简短的答案开始(而不是直接翻译),但随时可以跟进。

The solution for such problems in functional languages is usually reduce (often called fold). I will start with a short answer (and not a direct translation) but feel free to ask for a follow up.

以下方法通常不适用于函数式编程语言:

The approach below will typically not work in functional programming languages:

map = %{}
Enum.each [1, 2, 3], fn x ->
  Map.put(map, x, x)
end
map

最后的地图仍然是空的,因为我们不能改变数据结构。每次调用 Map.put(map,x,x)时,它将返回一个新地图。因此,我们需要在每次枚举后显式检索新地图。

The map at the end will still be empty because we can't mutate data structures. Every time you call Map.put(map, x, x), it will return a new map. So we need to explicitly retrieve the new map after each enumeration.

我们可以在Elixir中使用reduce来实现:

We can achieve this in Elixir using reduce:

map = Enum.reduce [1, 2, 3], %{}, fn x, acc ->
  Map.put(acc, x, x)
end

减少发出前一个函数的结果作为下一项的累加器。运行上面的代码后,变量 map 将为%{1 => 1,2 => 2,3 => 3}

Reduce will emit the result of the previous function as accumulator for the next item. After running the code above, the variable map will be %{1 => 1, 2 => 2, 3 => 3}.

由于这些原因,我们很少在枚举中使用每个。相反,我们使用 Enum 模块中的函数,它支持广泛的操作,最终在没有其他选择的情况下,又退回到 reduce

For those reasons, we rarely use each on enumeration. Instead, we use the functions in the Enum module, that support a wide range of operations, eventually falling back to reduce when there is no other option.

编辑:回答问题并通过更直接的代码翻译,这是您可以在检查时更新地图的方法:

to answer the questions and go through a more direct translation of the code, this what you can do to check and update the map as you go:

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

实际上,这里有一个集合会更好,所以让我们对其进行重构并在过程中使用一个集合:

In fact, a set would be better here, so let's refactor this and use a set in the process:

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

这篇关于Elixir-遍历并添加到地图的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆