Compare commits
	
		
			8 Commits
		
	
	
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| ae0efe0756 | |||
| 7f01af5d93 | |||
| 3d52397ef8 | |||
| 0c34a2df52 | |||
| 00336f0b55 | |||
| 5b1bd3e135 | |||
| 4a8e87f444 | |||
| 780eab521b | 
| @@ -1,15 +1,42 @@ | |||||||
| package TopSongs | package TopSongs | ||||||
| import scala.io.Source |  | ||||||
| import java.io.File | import java.io.File | ||||||
| import com.github.tototoshi.csv._ | import com.github.tototoshi.csv._ | ||||||
|  |  | ||||||
| trait Person: | trait Person { | ||||||
|   val name: String |   val name: String | ||||||
|  | } | ||||||
|  |  | ||||||
|  | case class Singer(name: String) extends Person | ||||||
|  |  | ||||||
| case class Artist(name: String) extends Person |  | ||||||
| case class Writer(name: String) extends Person | case class Writer(name: String) extends Person | ||||||
|  |  | ||||||
| case class Producer(name: String) extends Person | case class Producer(name: String) extends Person | ||||||
| class Album(title: String, label: String) |  | ||||||
|  | // The parametrized type Artist can be a Singer, a Writer or a Producer | ||||||
|  | // They do a different creation action | ||||||
|  | class Artist[A <: Person](val person: A) { | ||||||
|  |   def create(): String = { | ||||||
|  |     person match { | ||||||
|  |       case s: Singer => s"${s.name} sing" | ||||||
|  |       case w: Writer => s"${w.name} write" | ||||||
|  |       case p: Producer => s"${p.name} produce" | ||||||
|  |       case _ => s"${person.name} create" | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | // Defined a MusicGender as en enum | ||||||
|  | enum MusicGenre: | ||||||
|  |   case Rock, Soul, Blues, Folk, Funk, Reggae, HipHop, NewWave, Electro, Metal | ||||||
|  |  | ||||||
|  | // Define an Album with a union between a String and a MusicGenre | ||||||
|  | class Album(title: String, label: String, genre: String|MusicGenre) { | ||||||
|  |   def getGenre(): String | MusicGenre = { | ||||||
|  |      genre | ||||||
|  |   } | ||||||
|  | } | ||||||
|  |  | ||||||
| class Streak(val s: String) { | class Streak(val s: String) { | ||||||
|   val streak: Option[Int] = { |   val streak: Option[Int] = { | ||||||
|     val regex = "\\d+".r |     val regex = "\\d+".r | ||||||
| @@ -23,8 +50,9 @@ class Streak(val s: String) { | |||||||
|     } |     } | ||||||
|   } |   } | ||||||
| } | } | ||||||
|  |  | ||||||
| class Position(val p: String) { | class Position(val p: String) { | ||||||
|   val position: Option[Int] = { |   val pos: Option[Int] = { | ||||||
|     val regex = "\\d+".r |     val regex = "\\d+".r | ||||||
|     regex.findFirstIn(p) match { |     regex.findFirstIn(p) match { | ||||||
|       case Some(value) => Some(Integer.parseInt(value)) |       case Some(value) => Some(Integer.parseInt(value)) | ||||||
| @@ -33,55 +61,143 @@ class Position(val p: String) { | |||||||
|   } |   } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | // Defined a type alias Rank which is a tuple of Streak and Position | ||||||
|  | // Streak and Position are linked together, it's why there are regrouped in the Rank type alias | ||||||
|  | type Rank = (Streak, Position) | ||||||
|  |  | ||||||
|  | // Defined an intersection type of Artist & Writer & Producer | ||||||
|  | // Defined with an alias : God | ||||||
|  | // It's a way to define a type that is a combination of other types | ||||||
|  | // If an Artist is also a Writer and a Producer, it's basically a God of the music | ||||||
|  | type God = Singer & Writer & Producer | ||||||
|  |  | ||||||
| class Song( | class Song( | ||||||
|   val title: String, |   val title: String, | ||||||
|   val description: Option[String], |   val description: Option[String], | ||||||
|   val artist: List[Artist], |   val singer: List[Artist[Singer]], | ||||||
|   val writer: List[Writer], |   val writer: List[Artist[Writer]], | ||||||
|   val producer: List[Producer], |   val producer: List[Artist[Producer]], | ||||||
|   val album: Option[Album], |   val album: Option[Album], | ||||||
|   val streak: Streak, |   val rank: Rank | ||||||
|   val position: Position |  | ||||||
| ) | ) | ||||||
|  |  | ||||||
|  |  | ||||||
| object TopSongs { | case class TopSongs(songs: List[Song] = List()) { | ||||||
|   var songs: List[Song] = List() |   def addSong(song: Song): TopSongs = { | ||||||
|   def addSong(song: Song): Unit = { |     TopSongs(song :: songs) | ||||||
|     songs = song :: songs |  | ||||||
|   } |   } | ||||||
|   def printSongs(): Unit = { |   def printSongs(): Unit = { | ||||||
|     songs.foreach(song => println( |     songs.map(song => { | ||||||
|       s"${song.title} by ${song.artist.map(_.name).mkString(", ")} " + |       val title = song.title | ||||||
|         s"produced by ${song.producer.map(_.name).mkString(", ")} " + |       val singer = song.singer | ||||||
|         s"spent ${song.streak.streak.getOrElse("no")} weeks " + |       val producers = song.producer.map(_.create()).mkString(", ") | ||||||
|         s"on the charts on Pos. ${song.position.position.getOrElse("NA")}" |       val streak = song.rank._1.streak.getOrElse("no") | ||||||
|     )) |       val pos = song.rank._2.pos.getOrElse("NA") | ||||||
|  |  | ||||||
|  |       singer match { | ||||||
|  |         case s if s.exists(_.person.isInstanceOf[God]) => println(s"$title by God ${singer.map(_.person.name).mkString(", ")} spent $streak weeks on the charts on Pos. $pos") | ||||||
|  |         case _ => println( | ||||||
|  |           s"$title by ${singer.map(_.person.name).mkString(", ")}. " + | ||||||
|  |             s"$producers this song that " + | ||||||
|  |             s"spent $streak weeks " + | ||||||
|  |             s"on the charts on Pos. $pos" | ||||||
|  |         ) | ||||||
|       } |       } | ||||||
|  |     }) | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   // This function filter the songs by a specific music gender | ||||||
|  |   def filterByGenre(genre: MusicGenre): List[Song] = { | ||||||
|  |     songs.filter(song => song.album.exists(_.getGenre() == genre)) | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   // This function counts the number of songs by each artist | ||||||
|  |   // It uses flatMap to extract the artist names from the songs | ||||||
|  |   // Then it groups the songs by artist name and counts the occurrences | ||||||
|  |   // Finally, it returns a map with the artist names as keys and the counts as values | ||||||
|  |   def countSongsByArtist(): Map[String, Int] = { | ||||||
|  |     songs.flatMap(_.singer.map(_.person.name)) | ||||||
|  |       .groupBy(identity) | ||||||
|  |       .view.mapValues(_.size) | ||||||
|  |       .toMap | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   // This function return the song spent the most weeks on the chart | ||||||
|  |   // It uses reduce to find the song with the maximum streak value | ||||||
|  |   def longestStreak(): Song = { | ||||||
|  |     songs.reduce((s1, s2) => { | ||||||
|  |       if (s1.rank._1.streak.getOrElse(0) > s2.rank._1.streak.getOrElse(0)) s1 else s2 | ||||||
|  |     }) | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   // This function returns the top N songs by weeks on chart | ||||||
|  |   // It sorts the songs by the streak value in descending order and takes the top N songs | ||||||
|  |   def topNSongsByWeeks(n: Int): List[Song] = { | ||||||
|  |     songs.sortBy(song => -song.rank._1.streak.getOrElse(0)).take(n) | ||||||
|  |   } | ||||||
|  |  | ||||||
| } | } | ||||||
|  |  | ||||||
| @main def main(): Unit = | @main def main(): Unit = | ||||||
|   // create a new TopSongs object |   // create a new TopSongs object | ||||||
|   val topSongs = TopSongs |   var topSongs = TopSongs() | ||||||
|  |  | ||||||
|   val reader = CSVReader.open(new File("src/main/resources/songs.csv")) |   val reader = CSVReader.open(new File("src/main/resources/songs.csv")) | ||||||
|   val allRows = reader.allWithHeaders() |   val allRows = reader.allWithHeaders() | ||||||
|   for (row <- allRows) { |   for (row <- allRows) { | ||||||
|  |     val title = row("title") | ||||||
|  |     val description = row("description") | ||||||
|  |     val singer = List(Artist[Singer](Singer(row("artist")))) | ||||||
|  |     val writers = List(Artist[Writer](Writer(row("writers")))) | ||||||
|  |     val producers = List(Artist[Producer](Producer(row("producer")))) | ||||||
|  |     val album = Some(Album(row("appears on"), "NA", null)) | ||||||
|  |     val rank = (Streak(row("streak")), Position(row("position"))) | ||||||
|  |  | ||||||
|     val s = Song( |     val s = Song( | ||||||
|       title = row("title"), |       title = title, | ||||||
|       description = Some(row("description")), |       description = Some(description), | ||||||
|       artist = List(Artist(row("artist"))), |       singer = singer, | ||||||
|       writer = List(Writer(row("writers"))), |       writer = writers, | ||||||
|       producer = List(Producer(row("producer"))), |       producer = producers, | ||||||
|       album = Some(Album(row("appears on"), "NA")), |       album = album, | ||||||
|       streak = Streak(row("streak")), |       rank = rank | ||||||
|       position = Position(row("position")) |  | ||||||
|     ) |     ) | ||||||
|  |  | ||||||
|     // add the song to the TopSongs object |     // add the song to the TopSongs object | ||||||
|     topSongs.addSong(s) |     topSongs = topSongs.addSong(s) | ||||||
|   } |   } | ||||||
|   reader.close() |   reader.close() | ||||||
|  |  | ||||||
|  |   val foo: Boolean = topSongs.songs.exists(s => s.rank._1.streak.contains(1)) | ||||||
|  |  | ||||||
|   // print the songs |   // print the songs | ||||||
|   topSongs.printSongs() |   topSongs.printSongs() | ||||||
|  |  | ||||||
|  |   println("----------") | ||||||
|  |  | ||||||
|  |   // print the number of songs by artist | ||||||
|  |   val songsByArtist = topSongs.countSongsByArtist() | ||||||
|  |   println("Number of songs by artist:") | ||||||
|  |   songsByArtist.foreach { | ||||||
|  |     case (artist, count) => println(s"$artist: $count") | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   println("----------") | ||||||
|  |  | ||||||
|  |   // print the longest streak | ||||||
|  |   val longestStreakSong = topSongs.longestStreak() | ||||||
|  |   println(s"Longest streak: ${longestStreakSong.title} by ${longestStreakSong.singer.map(_.person.name).mkString(", ")} - ${longestStreakSong.rank._1.streak.getOrElse(0)} weeks") | ||||||
|  |  | ||||||
|  |   println("----------") | ||||||
|  |  | ||||||
|  |   // print the top N songs by weeks on chart | ||||||
|  |   val topNSongs = topSongs.topNSongsByWeeks(5) | ||||||
|  |   println("Top N songs by weeks on chart:") | ||||||
|  |   topNSongs.foreach { song => | ||||||
|  |     println(s"${song.title} by ${song.singer.map(_.person.name).mkString(", ")} - ${song.rank._1.streak.getOrElse(0)} weeks") | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user