Pensamiento al estilo Ramda: inmutabilidad y matrices

1. Primeros pasos
2. Combina las funciones
3. Uso parcial (curry)
4. Programación declarativa
5. Notación por excelencia
6. Inmutabilidad y objetos.
7. Inmutabilidad y matrices
8. lentes
9. Conclusión


Esta publicación es la séptima parte de una serie de artículos de programación funcional titulada Ramda Style Thinking.


En la sexta parte, hablamos sobre trabajar con objetos JavaScript en un estilo funcional e inmutable.


En esta publicación hablaremos sobre trabajos similares con matrices.


Lectura de elementos de matriz


En la sexta parte, aprendimos sobre las diversas funciones de Ramda para leer las propiedades de los objetos, como prop , pick y has . Ramda tiene aún más métodos para leer elementos de matriz.


El equivalente de prop para una matriz es nth ; el equivalente para pick es slice , y el equivalente para has es contiene . Echemos un vistazo a ellos.


 const numbers = [10, 20, 30, 40, 50, 60] nth(3, numbers) // => 40 (  ) nth(-2, numbers) // => 50 (     ) slice(2, 5, numbers) // => [30, 40, 50] (. ) contains(20, numbers) // => true 

Slice toma dos índices y devuelve una submatriz que comienza en el primer índice (comenzando desde cero) e incluye todos los elementos hasta el segundo índice, pero no incluye el elemento de este índice.


Obtener acceso al primer y último elemento de una matriz es bastante común, por lo que Ramda proporciona funciones cortas para estos casos, head y last . También proporciona funciones para obtener todos los elementos excepto el primero ( cola ), todos menos el último ( init ), los primeros N elementos ( take (N) ) y los últimos N elementos ( takeLast (N) ). Echemos un vistazo a ellos en acción.


 const numbers = [10, 20, 30, 40, 50, 60] head(numbers) // => 10 tail(numbers) // => [20, 30, 40, 50, 60] last(numbers) // => 60 init(numbers) // => [10, 20, 30, 40, 50] take(3, numbers) // => [10, 20, 30] takeLast(3, numbers) // => [40, 50, 60] 

Agregar, actualizar y eliminar elementos de matriz


Al estudiar cómo trabajar con objetos, aprendimos sobre las funciones assoc , dissoc y omit para agregar, actualizar y eliminar propiedades.


Dado que las matrices tienen una estructura de datos ordenada, tenemos varios métodos que hacen el mismo trabajo que la assoc de objetos. Los más comunes son insertar y actualizar , pero Ramda también proporciona métodos de agregar y anteponer para casos típicos de agregar elementos al principio y al final de una matriz. insert , append y prepend agregar nuevos elementos a la matriz; update "reemplaza" un elemento específico en la matriz con un nuevo valor.


Como puede esperar de una biblioteca funcional, todas estas funciones devuelven una nueva matriz con los cambios esperados; La matriz original nunca cambia.


 const numbers = [10, 20, 30, 40, 50, 60] insert(3, 35, numbers) // => [10, 20, 30, 35, 40, 50, 60] append(70, numbers) // => [10, 20, 30, 40, 50, 60, 70] prepend(0, numbers) // => [0, 10, 20, 30, 40, 50, 60] update(1, 15, numbers) // => [10, 15, 30, 40, 50, 60] 

Para combinar dos objetos en uno, aprendimos previamente sobre el método de merge . Ramda también proporciona un método concat para realizar la misma operación con matrices.


 const numbers = [10, 20, 30, 40, 50, 60] concat(numbers, [70, 80, 90]) // => [10, 20, 30, 40, 50, 60, 70, 80, 90] 

Observe que la segunda matriz se ha unido a la primera. Esto parece lógico cuando se utiliza este método por separado de otro código, pero, al igual que con la merge , esta lógica puede no conducir exactamente a lo que esperaríamos si utilizamos este método en nuestra tubería. Me pareció útil escribir una función auxiliar, concatAfter : const concatAfter = flip(concat) , para usarla en mis tuberías.


Ramda también ofrece varias opciones para eliminar elementos. remove elimina elementos por su índice, mientras que sin los elimina por su valor. También hay métodos como drop y dropLast para casos típicos cuando eliminamos elementos desde el principio o el final de una matriz.


 const numbers = [10, 20, 30, 40, 50, 60] remove(2, 3, numbers) // => [10, 20, 60] without([30, 40, 50], numbers) // => [10, 20, 60] drop(3, numbers) // => [40, 50, 60] dropLast(3, numbers) // => [10, 20, 30] 

Tenga en cuenta que remove acepta un índice y una cantidad, mientras que slice acepta dos índices. Esta inconsistencia puede ser confusa si no la conoce.


Conversión de elementos


Al igual que con los objetos, es posible que deseemos actualizar el elemento de matriz aplicando la función al valor original.


 const numbers = [10, 20, 30, 40, 50, 60] //      10 update(2, multiply(10, nth(2, numbers)), numbers) // => [10, 20, 300, 40, 50, 60] 

Para simplificar este caso típico, Ramda proporciona un método de ajuste que funciona como evolve para los objetos. Pero a diferencia de evolve , el adjust funciona con solo un elemento de la matriz.


 const numbers = [10, 20, 30, 40, 50, 60] //      10 adjust(multiply(10), 2, numbers) 

Tenga en cuenta que los dos primeros argumentos para adjust van al revés al compararlos con la update . Esto puede ser una fuente de errores, pero tiene sentido cuando considera una aplicación parcial. Es posible que desee realizar un adjust(multiply(10)) por usted mismo y, posteriormente, decidir qué índice de la matriz va a cambiar al usarlo.


Conclusión


Ahora tenemos herramientas para trabajar con matrices y objetos en un estilo declarativo e inmutable. Esto nos permite crear programas que consisten en bloques de construcción pequeños y funcionales, combinando funciones que harán lo que necesitamos, y todo esto sin cambiar todas nuestras estructuras de datos.


Siguiente


Hemos aprendido a leer, actualizar y transformar propiedades de objetos y elementos de matrices. Ramda proporciona otras herramientas básicas para realizar estas operaciones, lentes. El siguiente artículo sobre lentes nos mostrará cómo funcionan.

Source: https://habr.com/ru/post/es415025/


All Articles