Programación funcional y reactiva - Computación
Archivos CSV
Archivos CSV
"Ejemplo de texto", 123, 456
Descripción
Archivos CSV y Scala
Ejemplo
Año,Marca,Modelo,Descripción,Precio
1997,Ford,E350,"ac, abs, moon",3000.00
1999,Chevyr,Venture,Extended Edition,4900.00
1999,Chevy,Venture,"Extended Edition, Very Large",5000.00
1996,Jeep,Grand Cherokee,"MUST SELL! air, moon roof, loaded",4799.00
Archivos CSV y Scala
kantan.csv (https://nrinaudo.github.io/kantan.csv/)
kantan compatible RFC 4180
Resultados Right o Left
Librería
scalaVersion := "2.13.12"
// Core library
libraryDependencies += "com.nrinaudo" %% "kantan.csv" % "0.6.1"
import kantan.csv._
import kantan.csv.ops._
// import kantan.csv.generic._
import java.io.File
Archivos CSV y Scala
Leer filas como colección
val path2DataFile = "TemperaturasPromedioDecadas.csv"
val dataSource = new File(path2DataFile).asCsvReader[List[Int]](rfc)
dataSource.foreach(println _)
1980, 23, 13, 10, 22, 27, 6, 12, 16, 15, 16, 28, 15
1990, 5, 14, 14, 24, 16, 5, 15, 4, 5, 27, 5, 25
2000, 24, 11, 20, 13, 22, 12, 5, 15, 7, 17, 5, 8
2010, 18, 16, 6, 13, 20, 18, 21, 24, 13, 17, 18, 7
2020, 7, 7, 15, 7, 11, 14, 28, 20, 13, 23, 20, 8
Cada fila se leerá como una lista de números
enteros
para aplicar reglas del RFC 4180
No todos son números
Muchos CSV contienen varios tipos de datos, incluyendo nombres de columnas.
Kantan
Leer filas como tuplas
val path2DataFile2 = "EstudioPoblacionLojaGeneroArea.csv"
val dataSource1 = new File(path2DataFile2).readCsv[List, (String, Int, Int, Int, Int, Int, Int)](rfc)
dataSource1.foreach(println _)
val path2DataFile2 = "EstudioPoblacionLojaGeneroArea.csv"
val dataSource1 = new File(path2DataFile2).readCsv[List, (String, Int, Int, Int, Int, Int, Int)](rfc)
dataSource1.foreach(println _)
Kantan
Leer filas como tuplas e indicar si existe cabecera de columnas
val path2DataFile2 = "EstudioPoblacionLojaGeneroArea.csv"
val dataSource1 = new File(path2DataFile2).readCsv[List, (String, Int, Int, Int, Int, Int, Int)](rfc.withHeader(true))
dataSource1.foreach(println _)
JUGADOR;CLUB;NACIONALIDAD;GOLES;AUTOGOL
AGUIRRE SOTO RODRIGO SEBASTIAN;L.D.U.QUITO;URUGUAYA;12;No
ALEMAN ALEGRIA CHRISTIAN FERNANDO;BARCELONA S.C.;ECUATORIANA;6;No
ALVARADO CARRIEL ALEXANDER ANTONIO;S.D.AUCAS;ECUATORIANA;1;No
ALVEZ SAGAR JONATAN DANIEL;BARCELONA S.C.;URUGUAYA;2;No
AMARILLA LENCINA LUIS ANTONIO;U.CATOLICA;PARAGUAYA;16;No
AMIEVA JUAN MARTIN;MUSHUC RUNA S.C.;ARGENTINA;4;No
ANANGONO LEON JUAN LUIS;L.D.U.QUITO;ECUATORIANA;3;No
ANGULO ARROYO DANIEL PATRICIO;C.S.EMELEC;ECUATORIANA;5;No
ANGULO MEDINA JULIO EDUARDO;L.D.U.QUITO;ECUATORIANA;1;No
ANGULO TENORIO BRYAN DENNIS;C.S.EMELEC;ECUATORIANA;5;No
Kantan
Separador diferente a la coma
val path2DataFile2 = "Goleadores_LigaPro_2019.csv"
val dataSource2 = new File(path2DataFile2).readCsv[List, (String, String, String, Int, String)](rfc.withHeader(true).withCellSeparator(';'))
dataSource2.foreach(println _)
Collector
Es una función que se aplica en colecciones.
val values = List(1, "A", 2, "B")
values: List[Any] = List(1, A, 2, B)
Es una función que recibe una función parcial como parámetro y la aplica a todos los elementos de la colección. Su objetivo es crear una nueva colección que contenga únicamente aquellos elementos que cumplen con la función parcial.
Trabajo básico con datos
Seleccionar filas válidas
val path2DataFile2 = "Goleadores_LigaPro_2019.csv"
val dataSource2 = new File(path2DataFile2).readCsv[List, (String, String, String, Int,
String)](rfc.withHeader(true).withCellSeparator(';'))
val rows = dataSource2.collect({ case Right(goleador) => goleador })
Es posible que algunos datos no se asignen el formato especificado y sean procesados con Left.
- Esos datos se podría dejar de lado mientras se soluciona
- Se debería trabajar únicamente con los datos Rigth
Trabajo básico con datos
Seleccionar filas válidas
val path2DataFile2 = "Goleadores_LigaPro_2019.csv"
val dataSource2 = new File(path2DataFile2).readCsv[List, (String, String, String, Int,
String)](rfc.withHeader(true).withCellSeparator(';'))
val rows = dataSource2.collect({ case Right(goleador) => goleador })
Trabajo básico con datos
Contar las filas
val path2DataFile2 = "Goleadores_LigaPro_2019.csv"
val dataSource2 = new File(path2DataFile2).readCsv[List, (String, String, String,
Int, String)](rfc.withHeader(true).withCellSeparator(';'))
val rows = dataSource2.collect({ case Right(goleador) => goleador })
println(rows.length)
Trabajo básico con datos
Estadísticas básicas sobre enteros
val golesAvg = rows.map(_._4).sum / rows.length.toDouble
val numMayorGoles = rows.map(_._4).max
Trabajo básico con datos
¿Cuál es el número mayor de goles que han marcado por equipo? Inicie con un equipo.
Otras operaciones
Case class
Clases y objetos
Breve revisión
Clases y objetos
Clase y objetos java verbosos
Necesitamos escribir mucho código
Disponible a partir de Java 16
¿Scala tiene algo parecido?
Clase class
Descripción
Representación simple e inmutable de datos
Compilador crea varios métodos
case class CovidProvinceStats(provinceId: String, deaths: Int, confirmedCases: Int)
Clase class
Instancias
No se usa el operador new.
No se necesitan métodos de acceso
val lojaStats = CovidProvinceStats("11", 1400, 2909)
case class CovidProviceStats(provinceId: String, deaths: Int, confirmedCases: Int)
lojaStats.provinceId
val lojaStats = CovidProvinceStats("11", 1400, 2909)
Clase class
Métodos utiles
copy
Tupled
val elOroStats = lojaStats.copy("12", 2400, 30456)
val tuple = ("17", 12000, 3455)
val quitoStats = (CovidProceStats.apply _).tupled(tuple)
Clase class
Representación
case Class CovidProvinceStats(pronviceId: String, deaths: Int, confirmedCases: Int)
Clase class
Representación
case Class CovidProvinceStats(pronviceId: String, deaths: Int, confirmedCases: Int)
Case class y Katan
CSV a case class
val golesAvg = rows.map(_._4).sum / rows.length.toDouble
Para tener un acceso más específico a las filas se puede usar case class
val golesAvg = rows.map(_.goles).sum / rows.length.toDouble
Además las tuplas tienen un límite de 22 elementos Tuple22
Case class y Katan
CSV a case class
scalaVersion := "2.13.7"
// Core library
libraryDependencies += "com.nrinaudo" %% "kantan.csv" % "0.6.1"
libraryDependencies += "com.nrinaudo" %% “kantan.csv-generic" % "0.6.1"
case class Ciudades(
Provincia: String,
Canton: String,
Parroquia: String,
Femenino: Int,
Masculino: Int
)
val dataSource = new File(path2DataFile).readCsv[List, Ciudades](rfc.withHeader)
val values = dataSource.collect({ case Right(ciudades) => ciudades })
permite mapear automáticamente un archivo CSV a una case class
Case class y Katan
Práctica
Usando los datos de los goleadores del copa ecuador 2019 crear una case clase que represente los datos y use kantan para leer los datos y representarlos como una lista de objetos (case class)
Case class y Katan
Definición de case class de movies
case class Movies(
adult: Boolean,
belongs_to_collection: String,
budget: Int,
....
)
Case class y Katan
Definición de object
object LecturaDatosProyectoIntegradorV3 extends App {
val path2DataFile2 = "data/pi_movies_small.csv"
// Configurar lectura del CSV con delimitador ';'
val dataSource2 = new File(path2DataFile2)
.readCsv[List, Movies2](rfc.withHeader.withCellSeparator(';'))
// Filtrar filas válidas
val rows = dataSource2.collect {
case Right(movie) => movie
}
}
Proyecto Integrador o Bimestral
Proyecto Integrador o bimestral
Entrega 1 - 9 de enero de 2025