#Este es un comentario porque empieza con #

#Esta es una celda de código. 

#Se ejecuta con ctrl+enter. Probalo.

#La función print puede imprimir varias cosas
print("Hola Mundo") #impresión de un string
print(4) # impresión de un número

#Intentá imprimir el string "IMAGENES":

"""
Explanation: Tutorial de Python con Jupyter Notebook
Objetivo: Aprender a realizar programas simples en Python utilizando cuadernos de Jupyter.
Conocimientos previos: Conocimientos de programación básica: variables, estructuras de control, funciones y matrices.
Python
Python es un lenguaje de alto nivel, multiparadigma y con tipado dinámico. 
Si bien se usa en varios ámbitos, recientemente se ha convertido en el lenguaje más utilizado para programación científica, junto con las librerías NumPy (matrices), Matplotlib (visualizar datos) y otras.
El tutorial no asume conocimiento de Python, pero tampoco explica el lenguaje en detalle; se hace énfasis en cómo manipular matrices para procesar imágenes.
Cuadernos de Jupyter Notebook
La forma tradicional de correr un programa en python es con el comando python nombre.py, donde nombre.py es un archivo con código fuente python. 
En lugar de eso, para este curso utilizaremos un servidor de Jupyter Notebook con cuadernos de código. Estos cuadernos (notebooks) nos permiten combinar texto y código, organizados en celdas, lo cual es más cómodo para probar cosas nuevas y documentar lo que hacemos. 
El servidor de cuadernos se inicia ejecutando jupyter notebook desde la línea de comandos. 
Si tenemos cuadernos para abrir, antes de correr ese comando debemos ir al directorio con los cuadernos, de modo de poder abrirlos después. El servidor corre continuamente mientras usamos los cuadernos.
Una vez que el servidor corre y se abre el navegador, podés elegir abrir un cuaderno anterior o crear uno nuevo. Luego, se escribe y ejecuta texto y código en el cuaderno, y podés salvar el estado de un cuaderno con ctrl+s en cualquier momento. Se guarda tanto el código como el resultado de las ejecuciones.
Tenemos una guía de instalación disponible para que puedas correr python y jupyter en tu computadora.
Uso de Cuadernos de Jupyter
Los cuadernos tienen dos tipos de celdas, de código y de texto. La celda que estás leyendo es una celda de texto escrita con Markdown, un lenguaje de marcado parecido al que utiliza wikipedia para sus páginas o al HTML.
Las celdas de código son ejecutables, es decir, se pueden correr individualmente (con ctrl+enter o desde el menu Cell -&gt; Run Cells)
End of explanation
"""


x="hola"
print(x)

x=5
print(x)

y=x+2.5
print(y)

"""
Explanation: Python básico
Las variables en python no necesitan ser declaradas, simplemente se definen al ser utilizadas por primera vez. Además, (si bien no es recomendable) pueden cambiar de tipo volviendo a definir.
End of explanation
"""


### Enteros ###

x = 3 

print("- Tipo de x:")
print(type(x)) # Imprime el tipo (o `clase`) de x
print("- Valor de x:")
print(x)       # Imprimir un valor
print("- x+1:")
print(x + 1)   # Suma: imprime "4"
print("- x-1:")
print(x - 1)   # Resta; imprime "2"
print("- x*2:")
print(x * 2)   # Multiplicación; imprime "6"
print("- x^2:")
print(x ** 2)  # Exponenciación; imprime "9"
# Modificación de x
x += 1 
print("- x modificado:")
print(x)  # Imprime "4"

x *= 2
print("- x modificado:")
print(x)  # Imprime "8"

print("- Varias cosas en una línea:")
print(1,2,x,5*2) # imprime varias cosas a la vez



### Flotantes ###

y = 2.5 
print("- Tipo de y:")
print(type(y)) # Imprime el tipo de y
print("- Varios valores en punto flotante:")
print(y, y + 1, y * 2.5, y ** 2) # Imprime varios números en punto flotante

"""
Explanation: Tipos de datos básicos
Python tiene los mismos datos básicos que otros lenguajes: enteros, flotantes, strings y booleanos. Además, las listas son un tipo predefinido en el lenguaje.
Numeros
Python tiene soporte para números enteros y de punto flotante.
End of explanation
"""


### Booleanos ###

v1 = True #el valor verdadero se escribe True 
v2 = False #el valor verdadero se escribe False

print("- Valores de v1 y v2:")
print(v1,v2)

print("- Tipo de v1:")
print(type(v1)) # Imprime la clase de un valor booleano ('bool')

print("- v1 and v2:")
print(v1 and v2) # y lógico; imprime False
print(v1 or v2)  # o lógico; imprime True
print(not v1)   # negación lógica, imprime False

print(3 == 5)  # Imprime False ya que son distintos
print(3 != 5)  # Imprime True ya que son distintos
print(3 < 5)  # Imprime True ya que 3 es menor que 5



"""
Explanation: Booleanos
Python implementa todos los operadores usuales de la lógica booleana, usando palabras en inglés (and, or, not) en lugar de símbolos (||, &&, !, etc)
También tiene los típicos operadores de comparación: &lt;,&gt;,&gt;=,&lt;=,==,!=
End of explanation
"""


print("- Lista con 4 números:")
a=[57,45,7,13] # una lista con cuatro números
print(a)

print("- Lista con 3 strings:")
b=["hola","chau","buen día"] # una lista con tres strings
print(b)

# la función `len` me da la longitud de la lista
print("- Longitud de la lista:")
n=len(a)
print(n)

#Para acceder a sus elementos, se utiliza el []
# Los índices comienzan en 0
print("- Elemento con índice 0 de la lista:")
print(b[0])
print("- Elemento con índice 1 de la lista:")
print(b[1])
print("- Elemento con índice 2 de la lista:")
print(b[2])


# para crear una lista vacía, (sin elementos), simplemente ponemos []
vacia=[]
print("Lista vacía:")
print(vacia)

# También podés crear una sub-lista o slice especificando un rango de indices
print("- Elementos del índice 0 al 1 (2-1):")
print(a[0:2])
print("- Elementos del índice 1 al 3 (4-1):")
print(a[1:4])
#Si ponés nada antes del : se asume que pusiste 0
print("- Elementos desde el comienzo al indice 1 (2-1) :")
print(a[:2])
#Si no ponés nada después del : se asume que tomás todos hasta el final
print("- Elementos desde el indice 1 hasta el final:")
print(a[1:])

#Si no pones nada ni antes ni después es como tomar todo
print("- Todos los elementos:")
print(a[:])


#Si el fin es igual al comienzo, es un rango vacío, por ende se obtiene una lista vacía
print("- Rango vacío -> lista vacía:")
print(a[2:2])

"""
Explanation: Listas
Python tiene soporte para listas como un tipo predefinido del lenguaje. 
Para crear una lista basta con poner cosas entre [] (corchetes) y separarlas con , (comas).
End of explanation
"""


#por último, le podés agregar elementos a una lista con el método `append`
print("- Una lista con 3 strings:")
a=['una','lista','de']
print(a)

print("- La misma lista luego de agregarle un string más:")
a.append('strings')
print(a)

"""
Explanation: Una lista es un objeto
Python permite definir clases y crear objetos de esas clases, pero esos temas están fuera de este tutorial. No obstante, una lista es un objeto, y tiene varios métodos. Entre ellos está el método append, que permite agregar un elemento a la lista. Los métodos se invocan de la siguiente forma objeto.metodo(parametro1,parametro2,...).
End of explanation
"""


#Podés crear una tupla con valores entre () separados por ,
a=(1,2,57,4)
print("- Una tupla de cuatro elementos:")
print(a)
print("- El elemento con índice 2:")
print(a[2])
print("- Los elementos entre los índices 0 y 2:")
print(a[0:2])

# la siguiente línea genera un error de ejecución
#a.append(28)

"""
Explanation: Tuplas
Las tuplas son como las listas, pero no se pueden modificar. Son como unas listas de sólo lectura. Se crean con () (paréntesis) en lugar de [] (corchetes).
End of explanation
"""


edad = 25

print("La persona es")
if edad < 18: # el if termina con : para indicar donde acaba la condición
    # el print va indentado con 4 espacios para indicar que está dentro del
    # cuerpo del if
    print("Menor") 
else:
    #Lo mismo con este print
    print("Mayor")
    
print("De edad")
    

#Ejercicio
# Pasar a escala de grises el color codificado en los elementos de la lista `pixel`

pixel= [0.6,0.3,0.4] # intensidades de cada canal. 
#El elemento 0 es el R, el 1 el G y el 2 el B

# la intensidad en escala de grises es el promedio de la intensidad de cada canal R, G y B
#IMPLEMENTAR - COMIENZO
intensidad=(pixel[0]+pixel[1]+pixel[2])/3
#IMPLEMENTAR - FIN

print("La intensidad es:")
print(intensidad)

    

#Ejercicio
# Pasar a blanco y negro el valor de intensidad codificado en la variable intensidad


# podemos considerar que un pixel se convierte en blanco si su intensidad en escala de grises es mayor a 0.5
# y negro de lo contrario
#IMPLEMENTAR - COMIENZO
if intensidad>0.5:
    bw=1
else:
    bw=0
#IMPLEMENTAR - FIN

print("En blanco y negro el pixel sería: (0 -> negro, 1 -> blanco)")
print(bw)


"""
Explanation: Estructuras de control
En Python no hay llaves ({}) ni begin...end para marcar el comienzo y fin de un bloque, sino que eso se logra con la indentación. La indentación por defecto son 4 espacios en blanco.
Entonces va a ser necesario indentar correctamente para utilizar sentencias if, for o para definir funciones.
if
El if es como el de otros lenguajes, pero no pide paréntesis y termina con :. Su sintaxis es:
if condicion :
    cuerpo del if (indentado con 4 espacios)
else:
    cuerpo del else (indentado con 4 espacios)
End of explanation
"""


print("- Impresion de los elementos de la lista:")

# Imprimir los strings de mi_lista por separado
mi_lista=["img","python","numpy"]
for s in mi_lista:
    print(s)# este print va con indentación
    
#calcular la suma de los números e imprimirla
suma=0
mis_numeros=[5,8,17,12]
for numero in mis_numeros:
    suma=suma+numero
print("- La suma de los números es:")
print(suma)

"""
Explanation: For
Los for son parecidos a los if, pero tienen la sintaxis for variable in lista:. En este caso, variable es la variable que va a ir cambiando, y lista es una lista de python (o un iterable que es parecido)
End of explanation
"""



#un for de 0 a 3, para imprimir esos valores
print("Un for de 0 a 3")
for i in range(4):
    print(i)
    
#En Python los índices comienzan en 0, y por eso los rangos también.
    

#También se puede comenzar el rango en otro valor en lugar de 0
print("- Un for de 2 a 5:")
for j in range(2,6):
    print(j)



#Ejercicio: Escribir un for para buscar el máximo de la lista e imprimirlo
lista=[44,11,15,29,53,12,30]
maximo=0

# IMPLEMENTAR - COMIENZO
for val in lista:
    if val > maximo:
        maximo = val
# IMPLEMENTAR - FIN

print("- El maximo es:")
print(maximo)
# debe imprimir 53

#Ejercicio: Escribir un for para buscar el máximo de la lista e imprimir su _posición_
lista=[44,11,15,29,53,12,30]
posicion=0

# IMPLEMENTAR - COMIENZO
maximo=0
n=len(lista)
for i in range(n):
    if lista[i] > maximo:
        posicion=i
        maximo=val
# IMPLEMENTAR - FIN

print("- La posición del máximo es:")
print(posicion)
#debe imprimir 4

"""
Explanation: Cuando no tenemos una lista y queremos hacer un for "común" y que la variable que cambia sea un número que va incrementándose, podemos utilizar la función range.
End of explanation
"""


#esta funcion recibe dos números y devuelve su suma

def sumar(a,b):
    return a+b


c=sumar(2,5)
print("2+5=")
print(c)


#esta funcion recibe una lista y devuelve la suma de sus elementos
def sumar_todos(lista):
    suma=0
    for v in lista:
        suma+=v
    return suma

mi_lista=[54,12,99,15]
print("los elementos de la lista suman:")
print(sumar_todos(mi_lista))




#Ejercicio
# Escribir una función que reciba una lista y un valor, 
#y devuelva la cantidad de veces que aparece ese valor en la lista

def ocurrencias(lista,valor):
    #IMPLEMENTAR
    resultado=0
    for v in lista:
        if v==valor:
            resultado+=1
    return resultado


l=[1,4,2,3,5,1,4,2,3,6,1,7,1,3,5,1,1,5,3,2]
v=2

print("La cantidad de ocurrencias es:")
print(ocurrencias(l,v))
#debe imprimir 3, la cantidad de veces que aparece el 2 en la lista

"""
Explanation: Funciones
Las funciones se definen con la palabra clave def y tienen la sintaxis def nombre_funcion(parametros):. Para devolver un valor utilizamos la palabra clave return.
End of explanation
"""


