Las estructuras de datos de elixir son inmutables. Esto es excelente desde el punto de vista de la creencia de que nuestros datos no se corromperán más allá del reconocimiento en alguna otra pieza de código irrelevante, pero es un poco molesto cuando necesitamos cambiar una estructura profundamente anidada.
Tenemos una brillante abstracción de Access
, que simplifica enormemente cuatro operaciones básicas en objetos profundamente anidados utilizando las funciones exportadas por defecto desde Kernel
:
Estos cuatro mosqueteros (y d'Artagnan Kernel.get_and_update_in/{2,3}
generalmente se usan de la siguiente manera:
iex> users = %{"john" => %{age: 27, mood: ""}, "meg" => %{age: 23}}
Es conveniente y funciona en muchos casos ... excepto en aquellos en los que no funciona. Para usar Access
, debe conocer la ruta al elemento de destino, y todo esto requiere una cantidad significativa de código repetitivo para actualizar varios valores anidados a la vez (por ejemplo, eliminar todas las hojas con el valor nil
o destacar el contenido de todos los campos que no es necesario mostrar en los registros).
Para proporcionar descuentos al por mayor en el trabajo con estructuras anidadas, se creó la biblioteca Iteraptor
.
TL; DR:
Iterando todo lo que puedes iterar mágicamente en Elixir . Para que sea iterable, simplemente implemente el protocolo Enumerable
para este tipo en particular. Puedes agrupar pasajes en tuberías, mapear, reducir, filtrar, diluir ... Perdona mi francés, sí. Todos los que pasaron al menos ocho horas con Elixir definitivamente vieron (e incluso posiblemente escribieron) algo como esto:
~w| | |> Enum.map(&String.capitalize/1) |> Enum.each(fn capitalized_name -> IO.puts "Hello, #{capitalized_name}!" end)
Es realmente muy conveniente. Sin embargo, el código se vuelve rápidamente engorroso cuando se trata de estructuras profundamente anidadas, como un mapa con palabras clave anidadas, listas, etc. Un buen ejemplo de esto es cualquier archivo de configuración que contenga subsecciones anidadas.
El número de preguntas en Stack Overflow con la pregunta "¿cómo puedo cambiar la estructura anidada?" Me obligó a crear finalmente esta biblioteca. La implementación en Elixir parece un poco confusa, porque todo lo que hay a su alrededor es inmutable, y no puedes simplemente bajar las ramas de la estructura hasta las hojas, cambiando todo lo que necesitas en su lugar. Necesitará una batería, como, sin embargo, debajo de cualquier capó de un código funcional. El cambio de estructuras anidadas es probablemente el único ejemplo que he visto en mi vida cuando la mutabilidad facilita las cosas.
Como beneficio adicional a los precursores de mapas regulares, agregué una implementación para almacenar el valor en el interior de la estructura, lo que crea claves intermedias según sea necesario. Se comporta según lo propuesto, pero rechazado en ruby core Hash#bury
. Esta biblioteca también sabe cómo "jasonizar" estructuras anidadas que contienen palabras clave que no se pueden serializar simplemente en json , porque en su interior se presentan como listas de tuplas de dos elementos ( [foo: :bar] == [{:foo, :bar}]
), y las tuplas no son serializables fuera de la caja.
Entonces, saludemos a la biblioteca, que itera sobre cualquier mapa / palabra clave / lista en la cola y la mane es casi tan simple como el estándar Enum.each/2
y Enum.map/2
.
Las posibilidades
Las palabras no cuestan nada, ¡muestra el código!
Iteración, mapeo, reducción
Anidamiento profundo → estructura plana y viceversa
iex> %{a: %{b: %{c: 42, d: [nil, 42]}, e: [:f, 42]}} ...> |> Iteraptor.to_flatmap(delimiter: "_") #⇒ %{"a_b_c" => 42, "a_b_d_0" => nil, "a_b_d_1" => 42, "a_e_0" => :f, "a_e_1" => 42} iex> %{"abc": 42, "abd0": nil, "abd1": 42, "ae0": :f, "ae1": 42} ...> |> Iteraptor.from_flatmap
Bollos
iex> Iteraptor.jsonify([foo: [bar: [baz: :zoo], boo: 42]], values: true) %{"foo" => %{"bar" => %{"baz" => "zoo"}, "boo" => 42}} iex> Iteraptor.Extras.bury([foo: :bar], ~w|abcd|a, 42) [a: [b: [c: [d: 42]]], foo: :bar]
Las fuentes están abiertas , la documentación es bastante detallada , hemos estado en producción durante casi dos años.
¡Que tengas una buena iteración!