enumeration - what - traducir de ingles a español
Elixir: recorriendo y añadiendo al mapa (2)
Estoy reconstruyendo algo en Elixir a partir de algún código que construí en C #.
Fue bastante pirateado, pero funciona perfectamente (aunque no en Linux, por lo tanto, reconstruir).
Esencialmente, lo que hizo fue verificar algunos canales RSS y ver si había algún contenido nuevo. Este es el código:
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)
Me pregunto cómo puedo hacer una enumeración eficaz en Elixir. Además, parece que mi propio proceso de agregar cosas a "histórico" es la programación anti-funcional.
Obviamente, el primer paso fue declarar mi lista de URL, pero más allá de eso, la idea de la enumeración está jugando con mi cabeza. podria alguien ayudarme? Gracias.
Este es un buen desafío que tener y resolver definitivamente le dará una idea de la programación funcional.
La solución para tales problemas en los lenguajes funcionales suele ser reduce
(a menudo llamada fold
). Comenzaré con una respuesta corta (y no una traducción directa), pero no dude en solicitar un seguimiento.
El siguiente enfoque generalmente no funcionará en lenguajes de programación funcionales:
map = %{}
Enum.each [1, 2, 3], fn x ->
Map.put(map, x, x)
end
map
El mapa al final seguirá estando vacío porque no podemos mutar las estructuras de datos. Cada vez que llame a Map.put(map, x, x)
, devolverá un nuevo mapa. Entonces, necesitamos recuperar explícitamente el nuevo mapa después de cada enumeración.
Podemos lograr esto en Elixir usando reducir:
map = Enum.reduce [1, 2, 3], %{}, fn x, acc ->
Map.put(acc, x, x)
end
Reducir emitirá el resultado de la función anterior como acumulador para el siguiente artículo. Después de ejecutar el código anterior, el map
variable será %{1 => 1, 2 => 2, 3 => 3}
.
Por esas razones, rara vez usamos each
en la enumeración. En su lugar, usamos las funciones en el módulo Enum
, que admiten una amplia gama de operaciones, eventualmente retrocediendo para reduce
cuando no hay otra opción.
EDITAR: para responder las preguntas y pasar por una traducción más directa del código, esto es lo que puede hacer para verificar y actualizar el mapa a medida que avanza:
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
De hecho, un conjunto sería mejor aquí, así que vamos a refactorizar esto y usar un conjunto en el proceso:
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
Esto también podría ayudar:
count_animals_in_area = fn (area, acc) ->
acc = case Map.has_key?(area, "duck") do
true ->
Map.put(acc, "ducks", (acc["ducks"] + area["duck"]))
false ->
acc
end
acc = case Map.has_key?(area, "goose") do
true ->
Map.put(acc, "geese", (acc["geese"] + area["goose"]))
false ->
acc
end
acc = case Map.has_key?(area, "cat") do
true ->
Map.put(acc, "cats", (acc["cats"] + area["cat"]))
false ->
acc
end
acc
end
count_animals_in_areas = fn(areas) ->
acc = %{ "ducks" => 0,
"geese" => 0,
"cats" => 0 }
IO.inspect Enum.reduce areas, acc, count_animals_in_area
end
t1 = [ %{"duck" => 3, "goose" => 4, "cat" => 1},
%{"duck" => 7, "goose" => 2},
%{"goose" => 12}]
IO.puts "JEA: begin"
count_animals_in_areas.(t1)
IO.puts "JEA: end"
Salida:
iex(31)> c "count_animals.exs"
JEA: begin
%{"cats" => 1, "ducks" => 10, "geese" => 18}
JEA: end
[]
Estoy aprendiendo Elixir, por lo que lo anterior es, sin duda, subóptimo, pero espero que sea poco informativo.