Translate
jueves, 11 de enero de 2018
Encuesta de ecosistemas de Desarrolladores
El año pasado, en JetBrains realizamos una Encuesta de Ecosistemas de Desarrolladores para comprender mejor a los desarrolladores y sus necesidades en todo el mundo. 9,000 encuestados en todo el mundo nos dieron sus comentarios, y compartieron los datos más interesantes (así como datos brutos anonimizados) con la comunidad.
Este año estan haciendo otra encuesta, Developer Ecosystem Survey 2018, y necesitan tu ayuda nuevamente.
Y completando esta encuesta de 20 minutos tendremos la oportunidad de ganar un valioso premio: $ 1,000 para su educación, un certificado de Amazon de $ 100 o un paquete de regalo de sorpresa de JetBrains.
Como siempre, los ganadores serán elegidos al azar. Es bueno proporcionar respuestas significativas a las preguntas de la encuesta.
Dejo link: https://surveys.jetbrains.com/s3/c4-DevEcosystem18?gclid=EAIaIQobChMIy8HhiOXO2AIVVFMMCh3WCAQCEAEYASAAEgKnwvD_BwE
miércoles, 10 de enero de 2018
Lenguajes de programación para aprender en 2018
Quiero compartir un excelente articulo sobre lenguajes de programación en 2018 (es decir este año)
Si bien el articulo no presenta mayor sorpresa, lista los lenguajes más populares de 2017 y que seguirán fuerte en 2018. Ojo aparece Scala (esto me llamo mucho la atención)
Yo empece el año con Crystal y se lo recomiendo porque esta muy bueno el lenguaje.
Dejo link: https://platzi.com/blog/lenguajes-de-programacion-2018/?utm_source=facebook&utm_medium=paidsocial&utm_campaign=pubetapa0
Si bien el articulo no presenta mayor sorpresa, lista los lenguajes más populares de 2017 y que seguirán fuerte en 2018. Ojo aparece Scala (esto me llamo mucho la atención)
Yo empece el año con Crystal y se lo recomiendo porque esta muy bueno el lenguaje.
Dejo link: https://platzi.com/blog/lenguajes-de-programacion-2018/?utm_source=facebook&utm_medium=paidsocial&utm_campaign=pubetapa0
martes, 9 de enero de 2018
Juego de Serie en Crystal
Cuando quiero aprender un nuevo lenguaje desarrollo un juego de series, es decir aparece una serie con un valor faltante y el jugador debe completarlo.
Uno de los requerimientos no funcionales es que se pueda agregar una serie nueva fácilmente, para cumplirlo vamos a utilizar las ventajas de herencia y polimorfismo.
Vamos a desarrollar este juego en Crystal :
Comencemos haciendo un nuevo proyecto:
crystal init app secuenciaCrystal
cd secuenciaCrystal
y luego probamos compilar :
shards build
Y todo debería funcionar.
Ahora utilizaremos visual code con un plugin para crystal, para importar el proyecto, vamos a abrir carpeta y seleccionamos la carpeta donde estamos trabajando :
Ahora vamos a hacer un archivo secuencia.cr que va a tener las clases de secuencias:
abstract class Secuencia
@secuencia : Array(Int32)
getter secuencia
def initialize()
@secuencia = generarSecuencia()
end
abstract def generarSecuencia() : Array(Int32)
end
class SecuenciaPar < Secuencia
def generarSecuencia() : Array(Int32)
Array(Int32).new(4) { |i|
i * 2 * rand(100) + rand(10) * 2
}
end
end
class SecuenciaInPar < Secuencia
def generarSecuencia() : Array(Int32)
Array(Int32).new(4) { |i|
i * 2 * rand(100) + rand(10) * 2 + 1
}
end
end
Luego hacemos otro archivo para juego:
require "./secuencia.cr"
class Juego
getter puntos
@secuencia : Secuencia
def initialize()
@puntos = 0
@secuencia = generarSecuencia()
end
def generarSecuencia() : Secuencia
i = rand(2)
case i
when 0
SecuenciaPar.new
else
SecuenciaInPar.new
end
end
def valor1()
@secuencia.secuencia[0]
end
def valor2()
@secuencia.secuencia[1]
end
def valor4()
@secuencia.secuencia[3]
end
def esta_bien?(num : Int32?) : Bool
if @secuencia.secuencia[2] == num
@puntos = @puntos + 1
@secuencia = generarSecuencia()
true
else
@puntos = @puntos - 1
@secuencia = generarSecuencia()
false
end
end
end
Y por ultimo tenemos el programa propiamente dicho:
require "./secuenciaCrystal/*"
require "./juego.cr"
module SecuenciaCrystal
puts "Bienvenido a Secuancia Crystal"
juego = Juego.new
while true
puts juego.valor1.to_s + " " + juego.valor2.to_s + " ______ " + juego.valor4.to_s + " \n"
puts "Ingere el valor \n"
valorStr = gets.to_s
valor = (valorStr).to_i32
if juego.esta_bien?(valor)
puts " Ganaste !! Tus puntos : " + juego.puntos.to_s
else
puts " Perdiste !! Tus puntos : " + juego.puntos.to_s
end
puts "Ingere 0 para salir y otro valor para continuar"
if gets() == "0"
break
end
end
puts "Bye!"
end
Como se puede apreciar el diseño del juego permite generar una interfaz de consola o gráfica o en otra tecnología esta es la mayor ventaja de separar nuestros objetos de la capa de presentación.
Funcionando es muy divertido:
Dejo el repo: https://github.com/emanuelpeg/secuenciaCrystal
Funcionando es muy divertido:
Dejo el repo: https://github.com/emanuelpeg/secuenciaCrystal
domingo, 7 de enero de 2018
Primeros pasos con Crystal parte 2
Instalado el compilador y probado. Podemos empezar a hacer nuestro primer proyecto.
Para poder continuar el post con un ide un poco más comoda que nano, voy a usar el visual code con un pluging para Crystal. Es muy fácil instalar esto, van a complementos y buscan Crystal :
Si conocen otra IDE mejor, por favor comenten. Gracias.
Ahora voy a la consola y voy hacer mi proyecto:
crystal init app MiPrimerApp
Esto creo todo un proyecto ya listo para usar con git y con dependencias, versión y todo lo necesario :
Por ahora y solo por ahora, vamos a hacer un "Hola mundo" . Editamos MiPrimerApp.cr y escribimos:
require "./MiPrimerApp/*"
module MiPrimerApp
puts "Hola Mundo"
end
Luego en la consola entramos en la carpeta MiPrimerApp
cd MiPrimerApp
Ahora a ejecutar:
crystal deps
Para resolver las dependencias
crystal docs
Para generar la documentación.
shards build
Para compilar todo. (luego hablaremos de shards)
Si todo fue bien, podemos entrar a la carpeta bin y ejecutar nuestra aplicación:
cd bin/
./MiPrimerApp
Y listo!!
sábado, 6 de enero de 2018
Primeros pasos con Crystal
Ya instalado Crystal, vamos a comenzar haciendo un "Hola mundo"
Para hacer un ejemplo rápido vamos a utilizar la consola.
Primero con nano, vamos a hacer nuestro archivo que debe tener extensión .cr :
nano holaMundo.cr
Para hacer un ejemplo rápido vamos a utilizar la consola.
Primero con nano, vamos a hacer nuestro archivo que debe tener extensión .cr :
nano holaMundo.cr
Luego vamos a programar el hola mundo :
puts "Hola Mundo"
Luego salimos y guardamos.
Ahora vamos a compilar y ejecutar:
crystal holaMundo.cr
Si solo queremos ejecutar podemos hacer :
crystal run holaMundo.cr
Para generar un ejecutable debemos hacer :
crystal build holaMundo.cr
Luego podemos ejecutar nuestro programa con :
./holaMundo
Por defecto, los archivos ejecutables generados no están completamente optimizados. Para activar optimizaciones, se debe usar --release
crystal build holaMundo.cr --release
Si queremos no solo trabajar con un solo archivo sino hacer proyectos debemos utilizar el comando init pero eso sera en otro post.
Instalar Crystal en Linux
Para instalar Crystal en Linux es muy fácil.
Vamos por pasos:
Primero, debe agregar el repositorio a su configuración APT. Podemos hacerlo con este comando:
curl https://dist.crystal-lang.org/apt/setup.sh | sudo bash
Eso agregará la clave de firma y la configuración del repositorio. Si queremos hacerlo manualmente, ejecutamos los siguientes comandos como root:
apt-key adv --keyserver keys.gnupg.net --recv-keys 09617FD37CC06B54
echo "deb https://dist.crystal-lang.org/apt crystal main" > /etc/apt/sources.list.d/crystal.list
apt-get update
Una vez que el repositorio está configurado, estamos listo para instalar Crystal:
sudo apt-get install crystal
Algunas veces necesitará instalar el paquete build-essential para ejecutar o construir programas Crystal. Puedes instalarlo con el comando:
sudo apt-get install build-essential
Y Listo!!
Dejo link: https://crystal-lang.org/docs/installation/on_debian_and_ubuntu.html
Ruby + C = Crystal
Imaginate un lenguaje con la potencia de C pero la sintaxis de Ruby. En resumen eso es Crystal, un lenguaje con chequeo de tipos y sintaxis similar a Ruby.
Veamos un ejemplo:
# A very basic HTTP server
require "http/server"
server = HTTP::Server.new(8080) do |context|
context.response.content_type = "text/plain"
context.response.print "Hello world, got #{context.request.path}!"
end
puts "Listening on http://127.0.0.1:8080"
server.listen
Este pequeño ejemplo hemos montado un servidor web con una página de ejemplo.
Crystal tiene chequeo de tipo forma estática, por lo que el compilador detectará cualquier tipo de error antes de que falle en el tiempo de ejecución. Además, y para mantener el lenguaje limpio, Crystal tiene inferencia de tipos, por lo que no es necesario indicar el tipo la mayoría de las veces.
def shout(x)
# Notice that both Int32 and String respond_to `to_s`
x.to_s.upcase
end
foo = ENV["FOO"]? || 10
typeof(foo) # => (Int32 | String)
typeof(shout(foo)) # => String
Los tipos no permiten null y las variables nullable se representan como una unión entre el tipo y null. Como consecuencia, el compilador comprobará automáticamente si hay referencias nulas en tiempo de compilación.
if rand(2) > 0
my_string = "hello world"
end
puts my_string.upcase
Si corremos esto :
$ crystal hello_world.cr
Error in hello_world.cr:5: undefined method 'upcase' for Nil (compile-time type is (String | Nil))
puts my_string.upcase
Crystal posee un potente sistema de macro , que abarca desde la inspección básica de plantillas y AST hasta la inspección de tipos y la ejecución de programas externos arbitrarios.
class Object
def has_instance_var?(name) : Bool
{{ @type.instance_vars.map &.name.stringify }}.includes? name
end
end
person = Person.new "John", 30
person.has_instance_var?("name") #=> true
person.has_instance_var?("birthday") #=> false
Crystal usa hilos verdes, llamados fibras, para lograr concurrencia. Las fibras se comunican entre sí mediante canales, como en Go o Clojure, sin tener que recurrir a la memoria compartida o bloqueos.
channel = Channel(Int32).new
total_lines = 0
files = Dir.glob("*.txt")
files.each do |f|
spawn do
lines = File.read(f).lines.size
channel.send lines
end
end
files.size.times do
total_lines += channel.receive
end
puts total_lines
Crystal tiene una sintaxis dedicada para llamar fácilmente a bibliotecas nativas, eliminando la necesidad de volver a implementar tareas de bajo nivel.
# Fragment of the BigInt implementation that uses GMP
@[Link("gmp")]
lib LibGMP
alias Int = LibC::Int
alias ULong = LibC::ULong
struct MPZ
_mp_alloc : Int32
_mp_size : Int32
_mp_d : ULong*
end
fun init_set_str = __gmpz_init_set_str(rop : MPZ*, str : UInt8*, base : Int) : Int
fun cmp = __gmpz_cmp(op1 : MPZ*, op2 : MPZ*) : Int
end
struct BigInt < Int
def initialize(str : String, base = 10)
err = LibGMP.init_set_str(out @mpz, str, base)
raise ArgumentError.new("invalid BigInt: #{str}") if err == -1
end
def <=>(other : BigInt)
LibGMP.cmp(mpz, other)
end
end
Las bibliotecas de Crystal se empaquetan como fragmentos y se distribuyen a través de Git sin necesidad de un repositorio centralizado. Los comandos incorporados permiten que las dependencias se especifiquen fácilmente a través de un archivo YAML y se obtengan de sus respectivos repositorios.
name: my-project
version: 0.1
license: MIT
crystal: 0.21.0
dependencies:
mysql:
github: crystal-lang/crystal-mysql
version: ~> 0.3.1
Esto es solo un post de muestra. Para empezar de lleno vamos a tener que instalar el lenguaje y luego a estudiar, pero esos serán otros post.
Dejo link: https://crystal-lang.org/
https://github.com/crystal-lang/crystal/
Veamos un ejemplo:
# A very basic HTTP server
require "http/server"
server = HTTP::Server.new(8080) do |context|
context.response.content_type = "text/plain"
context.response.print "Hello world, got #{context.request.path}!"
end
puts "Listening on http://127.0.0.1:8080"
server.listen
Este pequeño ejemplo hemos montado un servidor web con una página de ejemplo.
Crystal tiene chequeo de tipo forma estática, por lo que el compilador detectará cualquier tipo de error antes de que falle en el tiempo de ejecución. Además, y para mantener el lenguaje limpio, Crystal tiene inferencia de tipos, por lo que no es necesario indicar el tipo la mayoría de las veces.
def shout(x)
# Notice that both Int32 and String respond_to `to_s`
x.to_s.upcase
end
foo = ENV["FOO"]? || 10
typeof(foo) # => (Int32 | String)
typeof(shout(foo)) # => String
Los tipos no permiten null y las variables nullable se representan como una unión entre el tipo y null. Como consecuencia, el compilador comprobará automáticamente si hay referencias nulas en tiempo de compilación.
if rand(2) > 0
my_string = "hello world"
end
puts my_string.upcase
Si corremos esto :
$ crystal hello_world.cr
Error in hello_world.cr:5: undefined method 'upcase' for Nil (compile-time type is (String | Nil))
puts my_string.upcase
Crystal posee un potente sistema de macro , que abarca desde la inspección básica de plantillas y AST hasta la inspección de tipos y la ejecución de programas externos arbitrarios.
class Object
def has_instance_var?(name) : Bool
{{ @type.instance_vars.map &.name.stringify }}.includes? name
end
end
person = Person.new "John", 30
person.has_instance_var?("name") #=> true
person.has_instance_var?("birthday") #=> false
Crystal usa hilos verdes, llamados fibras, para lograr concurrencia. Las fibras se comunican entre sí mediante canales, como en Go o Clojure, sin tener que recurrir a la memoria compartida o bloqueos.
channel = Channel(Int32).new
total_lines = 0
files = Dir.glob("*.txt")
files.each do |f|
spawn do
lines = File.read(f).lines.size
channel.send lines
end
end
files.size.times do
total_lines += channel.receive
end
puts total_lines
Crystal tiene una sintaxis dedicada para llamar fácilmente a bibliotecas nativas, eliminando la necesidad de volver a implementar tareas de bajo nivel.
# Fragment of the BigInt implementation that uses GMP
@[Link("gmp")]
lib LibGMP
alias Int = LibC::Int
alias ULong = LibC::ULong
struct MPZ
_mp_alloc : Int32
_mp_size : Int32
_mp_d : ULong*
end
fun init_set_str = __gmpz_init_set_str(rop : MPZ*, str : UInt8*, base : Int) : Int
fun cmp = __gmpz_cmp(op1 : MPZ*, op2 : MPZ*) : Int
end
struct BigInt < Int
def initialize(str : String, base = 10)
err = LibGMP.init_set_str(out @mpz, str, base)
raise ArgumentError.new("invalid BigInt: #{str}") if err == -1
end
def <=>(other : BigInt)
LibGMP.cmp(mpz, other)
end
end
Las bibliotecas de Crystal se empaquetan como fragmentos y se distribuyen a través de Git sin necesidad de un repositorio centralizado. Los comandos incorporados permiten que las dependencias se especifiquen fácilmente a través de un archivo YAML y se obtengan de sus respectivos repositorios.
name: my-project
version: 0.1
license: MIT
crystal: 0.21.0
dependencies:
mysql:
github: crystal-lang/crystal-mysql
version: ~> 0.3.1
Esto es solo un post de muestra. Para empezar de lleno vamos a tener que instalar el lenguaje y luego a estudiar, pero esos serán otros post.
Dejo link: https://crystal-lang.org/
https://github.com/crystal-lang/crystal/
jueves, 4 de enero de 2018
10 ebook populares del 2017
Me llego este mail y como la mayoría de los libros son gratuitos, lo quiero compartir:
miércoles, 3 de enero de 2018
Comparando F# con C# parte 2
Ahora, implementaremos un el algoritmo quicksort para ordenar listas y lo haremos en F# y C# para compararlos.
Para el que no conoce el algoritmo quicksort, vamos a ver la lógica:
Si la lista está vacía, no hay nada que hacer.
De otra manera:
- Tome el primer elemento de la lista, que lo llamaremos pivot
- Buscamos todos los elementos menores al pivot y los ordenamos usando el algoritmo quicksort.
- Buscamos todos los elementos mayores al pivot y los ordenamos usando el algoritmo quicksort.
- Combinamos las tres partes para obtener el resultado final: (elementos menores + pivot + elementos mayores)
Tenga en cuenta que hemos simplificado este algoritmo para hacer la explicación más simple.
Veamos el código en F#:
let rec quicksort list =
match list with
| [] -> // Si la lista es vacia
[] // retorna una lista vacia
| firstElem::otherElements -> // si no es vacia
let smallerElements = // toma los menores
otherElements
|> List.filter (fun e -> e < firstElem)
|> quicksort // y los ordena
let largerElements = // toma los mayores
otherElements
|> List.filter (fun e -> e >= firstElem)
|> quicksort // y los ordena
// concatena estas 3 partes y la retorna.
List.concat [smallerElements; [firstElem]; largerElements]
//test
printfn "%A" (quicksort [1;5;23;18;9;1;3])
Repasemos el código:
No hay declaraciones de tipos en ningún lado. Esta función funcionará en cualquier lista que tenga elementos comparables (que es casi todos los tipos F#, ya que automáticamente tienen una función de comparación predeterminada).
Toda la función es recursiva: esto se señala al compilador utilizando la palabra clave rec en "let rec quicksort list =".
Con match..with se esta usando pattern matching, las expresiones son como esta:
match x with
| caseA -> something
| caseB -> somethingElse
El pattern matching es una técnica que analiza objetos y ejecuta el código que corresponde (cuando el objeto aplica le patron)
De esta manera se pregunta si la lista es vacía, y si es vacía se retorna una lista vacía.
De lo contrario, aplica la lógica descrita anteriormente. Es decir filtra la lista de los menores por medio de una función anónima que se pasa como clausura, que indica como se va a filtrar y luego se ordena utilizando quicksort, luego filtra la lista de los mayores y los ordena . Y por ultimo se retorna la concatenación de estas 3 partes. ,
Veamos la implementación en C# sin LinQ :
public class QuickSortHelper
{
public static List<T> QuickSort<T>(List<T> values)
where T : IComparable
{
if (values.Count == 0)
{
return new List<T>();
}
// Tomamos el primer valor
T firstElement = values[0];
// Filtramos los elementos
var smallerElements = new List<T>();
var largerElements = new List<T>();
for (int i = 1; i < values.Count; i++) {
var elem = values[i];
if (elem.CompareTo(firstElement) < 0)
{
smallerElements.Add(elem);
}
else
{
largerElements.Add(elem);
}
}
result.AddRange(QuickSort(smallerElements.ToList()));
result.Add(firstElement);
result.AddRange(QuickSort(largerElements.ToList()));
return result;
}
}
Comparando los dos programas, nuevamente podemos ver que el código F# es mucho más compacto, con menos ruido y sin necesidad de declaraciones de tipo.
Además, el código F# se lee casi exactamente como es algoritmo, a diferencia del código C#. Esta es otra ventaja clave de F# - el código es generalmente más declarativo ("qué hacer") y menos imperativo ("cómo hacerlo") que C#, y por lo tanto es mucho más autodocumentado.
Veamos una versión más funcional en C#:
public static class QuickSortExtension
{
public static IEnumerable<T> QuickSort<T>(
this IEnumerable<T> values) where T : IComparable
{
if (values == null || !values.Any())
{
return new List<T>();
}
var rest = values.Skip(1);
.Where(i => i.CompareTo(firstElement) < 0)
.QuickSort();
var largerElements = rest
.Where(i => i.CompareTo(firstElement) >= 0)
.QuickSort();
return smallerElements
.Concat(new List<T>{firstElement})
.Concat(largerElements);
}
}
Esto es mucho más limpio, y lee casi lo mismo que la versión F#.
Finalmente, el código F# a menudo funciona la primera vez, mientras que el código C# puede requerir más depuración.
Pero incluso la ultima versión funcional C# tiene inconvenientes en comparación con la versión F#. Por ejemplo, como F# usa la coincidencia de patrones, no es posible derivar al caso de la "lista no vacía" con una lista vacía.
Dejo link: https://fsharpforfunandprofit.com/posts/fvsc-quicksort/
No hay declaraciones de tipos en ningún lado. Esta función funcionará en cualquier lista que tenga elementos comparables (que es casi todos los tipos F#, ya que automáticamente tienen una función de comparación predeterminada).
Toda la función es recursiva: esto se señala al compilador utilizando la palabra clave rec en "let rec quicksort list =".
Con match..with se esta usando pattern matching, las expresiones son como esta:
match x with
| caseA -> something
| caseB -> somethingElse
El pattern matching es una técnica que analiza objetos y ejecuta el código que corresponde (cuando el objeto aplica le patron)
De esta manera se pregunta si la lista es vacía, y si es vacía se retorna una lista vacía.
De lo contrario, aplica la lógica descrita anteriormente. Es decir filtra la lista de los menores por medio de una función anónima que se pasa como clausura, que indica como se va a filtrar y luego se ordena utilizando quicksort, luego filtra la lista de los mayores y los ordena . Y por ultimo se retorna la concatenación de estas 3 partes. ,
Veamos la implementación en C# sin LinQ :
public class QuickSortHelper
{
public static List<T> QuickSort<T>(List<T> values)
where T : IComparable
{
if (values.Count == 0)
{
return new List<T>();
}
// Tomamos el primer valor
T firstElement = values[0];
// Filtramos los elementos
var smallerElements = new List<T>();
var largerElements = new List<T>();
for (int i = 1; i < values.Count; i++) {
var elem = values[i];
if (elem.CompareTo(firstElement) < 0)
{
smallerElements.Add(elem);
}
else
{
largerElements.Add(elem);
}
}
result.AddRange(QuickSort(smallerElements.ToList()));
result.Add(firstElement);
result.AddRange(QuickSort(largerElements.ToList()));
return result;
}
}
Comparando los dos programas, nuevamente podemos ver que el código F# es mucho más compacto, con menos ruido y sin necesidad de declaraciones de tipo.
Además, el código F# se lee casi exactamente como es algoritmo, a diferencia del código C#. Esta es otra ventaja clave de F# - el código es generalmente más declarativo ("qué hacer") y menos imperativo ("cómo hacerlo") que C#, y por lo tanto es mucho más autodocumentado.
public static class QuickSortExtension
{
public static IEnumerable<T> QuickSort<T>(
this IEnumerable<T> values) where T : IComparable
{
if (values == null || !values.Any())
{
return new List<T>();
}
var rest = values.Skip(1);
.Where(i => i.CompareTo(firstElement) < 0)
.QuickSort();
var largerElements = rest
.Where(i => i.CompareTo(firstElement) >= 0)
.QuickSort();
return smallerElements
.Concat(new List<T>{firstElement})
.Concat(largerElements);
}
}
Esto es mucho más limpio, y lee casi lo mismo que la versión F#.
Finalmente, el código F# a menudo funciona la primera vez, mientras que el código C# puede requerir más depuración.
Pero incluso la ultima versión funcional C# tiene inconvenientes en comparación con la versión F#. Por ejemplo, como F# usa la coincidencia de patrones, no es posible derivar al caso de la "lista no vacía" con una lista vacía.
Dejo link: https://fsharpforfunandprofit.com/posts/fvsc-quicksort/
lunes, 1 de enero de 2018
Diferencia entre ArrayList y LinkedList en Java
Este post lo podría haber hecho hace mucho pero bueno hace poco que me he dado cuenta que esto no es de conocimiento de todos los mortales programadores java.
Antes que nada aclaro que tanto ArrayList como LinkedList implementan la interfaz List y se encuentran en el paquete java.util y son parte de lo que se conoce como java collection framework o jcf para los amigos.
La principal diferencia es un tema de implementación ArrayList implementa la lista con arreglos linkeados, lo que la hace muy eficiente para recorrer pero ineficiente para insertar o eliminar elementos que se no encuentren en el final. En cambio LinkedList es una lista de elementos linkeados (en realidad es una lista doblemente enlazada) lo que la hace lenta para recorrer pero sumamente eficiente para insertar o eliminar elementos. Esta es la principal diferencia y hay que recordarla siempre.
Por lo tanto ArrayList :
- usa internamente un arreglo dinámico para almacenar los elementos.
- proporciona una manipulación lenta
- es la mejor opción para almacenar y acceder a datos o elementos consecutivos.
Por lo tanto LinkedList:
- proporciona una manipulación más rápida porque utiliza una lista doblemente enlazada.
- se puede utilizar como lista y cola porque implementa interfaz de List, Deque y Queue.
- es mejor para manipulación de elementos, es decir, para insertar y eliminar elementos.
Por lo tanto si necesitamos agregar elementos consecutivos y recorrerlos debemos utilizar ArrayList y si en cambio necesitamos insertar y eliminar valores no consecutivos debemos usar LinkedList.
Veamos un ejemplo de ArrayList:
import java.util.*;
public class Sample {
public static void main(String args[]) {
//Declaring ArrayList
List<String> l = new ArrayList<String>();
l.add("Apple");//inserting elements
l.add("Orange");
l.add("Mango");
l.add("Banana");
l.add("Guava");
//Traverse the elements by using Iterator interface
Iterator i = l.iterator();
while(i.hasNext()) {
System.out.println(i.next());
}
}
}
Output: Apple
Orange
Mango
Banana
Guava
Veamos un ejemplo de LinkedList:
import java.util.*;
public class Demo {
public static void main(String args[]) {
//Declaring the LinkedList
LinkedList<String> ll = new LinkedList<String>();
ll.add("Red");
ll.add("Red");
ll.add("Black")';
ll.add("Blue");
ll.add("Pink");
ll.add("Green");
//Traversing elements by using Iterator interface
Iterator i = ll.iterator();
while(i.hasNext()) {
System.out.println(i.next())
}
}
}
Output: Red
Red
Black
Blue
Pink
Green
Dejo link:
domingo, 31 de diciembre de 2017
Feliz 2018 !!!
Feliz 2018, que todos tus sueños se cumplan, que aprendas mucho y que enseñes aun más.
Gracias por leer!!
sábado, 30 de diciembre de 2017
StringJoiner la nueva clase en Java 8
Java 8 se viene con todo y ahora vamos a ver la clase StringJoiner. Para que sirve? como su nombre lo indica se utiliza para construir una secuencia de caracteres separados por delimitadores, es decir, puede crear cadenas utilizando algunos delimitadores como "," (coma) y "-" (guión), etc. También podemos usar prefijos y sufijos para la secuencia de caracteres.
StringJoiner se encuentra en el paquete java.util y es una clase que es final y extiende de object.
Tiene 2 constructores:
- StringJoiner(CharSequence delimiter).
- StringJoiner(CharSequence delimiter, CharSequence prefix, CharSequence suffix).
En el primero solo le pasamos el delimitador y en el segundo le pasamos el delimitador, el prefijo y sufijo de la cadena que vamos a formar.
Entre los métodos más importantes podemos nombrar:
- StringJoiner add(CharSequence newElement) : Agrega un elemento
- int length() : cantidad de caracteres.
- StringJoiner merge(StringJoiner other): une 2 secuencias.
- StringJoiner setEmptyValue(CharSequence emptyValue) : Definimos que valor va a retornar si la secuencia en vacía.
- String toString() : Retorna la cadena
Veamos unos ejemplos:
import java.util.*;
class Demo {
public static void main(String args[]) {
StringJoiner sj = new StringJoiner(",");//passing comma (,) as delimiter
StringJoiner sj1 = new StringJoiner("-");//passing hyphen (-) as delimiter
//Adding some string with comma(,) delimiter
sj.add("suresh");
sj.add("gurpreet");
sj.add("piyush");
sj.add("jagdish");
System.out.println(sj);
System.out.println();
//Adding some string with hyphen(-) delimiter
sj1.add("simran");
sj1.add("siya");
sj1.add("khusboo");
sj1.add("barkha");
System.out.println(sj1);
}
}
Output: suresh,gurpreet,piyush,jagdish
simran-siya-khusboo-barkha
Recordemos que System.out.println utiliza el metodo toString para imprimir un objeto.
Veamos un ejemplo con sufijo y prefijo:
import java.util.StringJoiner;
class Demo1 {
public static void main(String args[]) {
//passing , as delimiter and using "(" opening bracket as prefix and ")" closing bracket as suffix.
StringJoiner sj = new StringJoiner(",","(",")");
sj.add("blue");
sj.add("red");
sj.add("pink");
sj.add("white");
System.out.println(sj);
}
}
Output: (blue,red,pink,white)
Veamos ahora un ejemplo con merge:
import java.util.*;
class Demo3 {
public static void main(String args[]) {
//Creating first StringJoiner with delimiter and prefix and suffix
StringJoiner sj1 = new StringJoiner(",","*","*");
sj1.add("rose");
sj1.add("lotus");
System.out.println(sj1);
//Creating second StringJoiner with delimiter and prefix and suffix
StringJoiner sj2 = new StringJoiner(":","*","*");
sj2.add("red");
sj2.add("pink");
System.out.println(sj2);
//Now using merge() method for merging sj1 and sj2 joiners
StringJoiner mrg = sj1.merge(sj2);
System.out.println(mrg);
}
}
Output: *rose,lotus*
*red:pink*
*rose,lous,red:pink*
Y por ultimo un ejemplo integrador:
import java.util.*;
class Demo4 {
public static void main(String args[]){
StringJoiner sj1 = new StringJoiner(",");
/* if StringJoiner is empty then we can print a massage for this StringJoiner by using setEmptyValue(). */
sj1.setEmptyValue("This is empty StringJoiner");
System.out.println(sj1);
System.out.println("add some values");
//now adding some string by using add() method
sj1.add("c++");
sj1.add("html");
System.out.println("added values is: "+sj1);
//After adding values, let's count the length of string by using length() method
int length = sj1.length();
System.out.println("Length of SJ "+length);
}
}
Output: This is empty StringJoiner
add some values
added values is: c++,html
Length of SJ 8
viernes, 29 de diciembre de 2017
Comparando F# con C#
Vamos a comparar C# con F# a traves de un ejemplo, una suma simple. El problema es simple: "sumar los cuadrados de 1 a N".
Primero, veamos el código F# :
// define the square function
let square x = x * x
// define the sumOfSquares function
let sumOfSquares n =
[1..n] |> List.map square |> List.sum
// try it
sumOfSquares 100
Y listo, como podemos ver podemos utilizar el operador |> para que la salida de una función, sea entrada de otra. Es similar a el operador |> de elixir.
Si vemos la linea: let sumOfSquares n = [1..n] |> List.map square |> List.sum
- Crea una lista de enteros de 1 a n.
- Luego toma esa lista y aplica una función square usando la biblioteca llamada List.map.
- Luego acumula todos los elementos de la lista resultante.
Ahora veamos una implementación en C# utilizando el estilo clásico (no funcional) :
public static class SumOfSquaresHelper
{
public static int Square(int i)
{
return i * i;
}
public static int SumOfSquares(int n)
{
int sum = 0;
for (int i = 1; i <= n; i++)
{
sum += Square(i);
}
return sum;
}
}
¿Cuáles son las diferencias?
- El código F# es más compacto
- El código F# no tenía ninguna declaración de tipo
- Con F# podemos desarrollar interactivamente
La diferencia más obvia es que hay mucho más código C#. 13 líneas en C# en comparación con 3 líneas en F# (ignorando los comentarios). El código C# tiene mucho "ruido", cosas como llaves, puntos y comas, etc. Y en C# las funciones no pueden estar solas, sino que deben agregarse a alguna clase ("SumOfSquaresHelper"). F# usa espacios en blanco en lugar de paréntesis, no necesita terminador de línea y las funciones pueden ser independientes.
En F#, es común que las funciones completas se escriban en una línea, como la función "cuadrada". La función sumOfSquares también podría haber sido escrita en una línea. En C# esto es mal visto y es considerado una mala práctica.
Cuando una función tiene múltiples líneas, F# usa indentación para indicar un bloque de código, lo que elimina la necesidad de llaves. (Si alguna vez ha usado Python, esta es la misma idea). Entonces la función sumOfSquares también podría haber sido escrita de esta manera:
let sumOfSquares n =
[1..n]
|> List.map square
|> List.sum
La siguiente diferencia es que el código C# tiene que declarar explícitamente todos los tipos utilizados. Por ejemplo, el parámetro n es de tipo int y el tipo de retorno SumOfSquares es int. Sí bien, C# permite usar la palabra clave "var" en muchos lugares, pero no para los parámetros y tampoco para tipos de funciones.
En el código F#, no declaramos ningún tipo. Este es un punto importante: F# parece un lenguaje sin tipo o de tipado dinámico, pero en realidad es igual de seguro que C#, de hecho, ¡aún más! F# usa una técnica llamada "inferencia de tipo" para inferir los tipos que está utilizando desde su contexto. Funciona increíblemente bien la mayor parte del tiempo, y reduce la complejidad del código inmensamente.
En este caso, el algoritmo de inferencia de tipo observa que comenzamos con una lista de enteros. Esto a su vez implica que la función cuadrada y la función suma también deben tomarse, y que el valor final debe ser un int. Puede ver cuáles son los tipos inferidos mirando el resultado de la compilación en la ventana interactiva. Verás algo como:
val square : int -> int
lo que significa que la función "cuadrado" toma un int y devuelve un int. Esta notación me recuerda mucho a Haskell o Scala.
Si la lista original hubiera utilizado flotantes en su lugar, el sistema de inferencia tipo habría deducido que la función cuadrada utilizada flotantes en su lugar:
// define the square function
let squareF x = x * x
// define the sumOfSquares function
let sumOfSquaresF n =
[1.0 .. n] |> List.map squareF |> List.sum // "1.0" is a float
sumOfSquaresF 100.0
¡La verificación de tipos es muy estricta! Si intenta usar una lista de flotantes ([1.0..n]) en el ejemplo original sumOfSquares, o una lista de ints ([1 ..n]) en el ejemplo sumOfSquaresF, obtendrá un error de tipo del compilador.
Finalmente, F# tiene una ventana interactiva donde puedes probar el código inmediatamente y jugar con él. En C# no hay una manera fácil de hacer esto.
Por ejemplo, puedo escribir mi función cuadrada e inmediatamente probarla:
// define the square function
let square x = x * x
// test
let s2 = square 2
let s3 = square 3
let s4 = square 4
Muchas personas afirman que el diseño de códigos impone de forma interactiva buenas prácticas de diseño, como el desacoplamiento y las dependencias explícitas, y por lo tanto, el código que es adecuado para la evaluación interactiva también será un código que es fácil de probar. Por el contrario, el código que no se puede probar de forma interactiva probablemente también sea difícil de probar.
El ejemplo anterior fue escrito usando C# viejo. C# ha incorporado muchas características funcionales, y es posible reescribir el ejemplo de una manera más compacta utilizando las extensiones LINQ.
Así que aquí hay otra versión C#:
public static class FunctionalSumOfSquaresHelper
{
public static int SumOfSquares(int n)
{
return Enumerable.Range(1, n)
.Select(i => i * i)
.Sum();
}
}
Sin embargo, además del ruido de las llaves, los puntos y los puntos y comas, la versión C# necesita declarar el parámetro y los tipos de retorno, a diferencia de la versión F#.
Si bien el ejemplo fue trivial, nos permitio revisar las deferencias entre F# y C#.
Dejo link: https://fsharpforfunandprofit.com/posts/fvsc-sum-of-squares//
Suscribirse a:
Entradas (Atom)