diff --git a/hw2/.idea/.gitignore b/hw2/.idea/.gitignore new file mode 100644 index 0000000..13566b8 --- /dev/null +++ b/hw2/.idea/.gitignore @@ -0,0 +1,8 @@ +# Default ignored files +/shelf/ +/workspace.xml +# Editor-based HTTP Client requests +/httpRequests/ +# Datasource local storage ignored files +/dataSources/ +/dataSources.local.xml diff --git a/hw2/.idea/hw2.iml b/hw2/.idea/hw2.iml new file mode 100644 index 0000000..d6ebd48 --- /dev/null +++ b/hw2/.idea/hw2.iml @@ -0,0 +1,9 @@ + + + + + + + + + \ No newline at end of file diff --git a/hw2/.idea/modules.xml b/hw2/.idea/modules.xml new file mode 100644 index 0000000..b3c4100 --- /dev/null +++ b/hw2/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/hw2/.idea/vcs.xml b/hw2/.idea/vcs.xml new file mode 100644 index 0000000..6c0b863 --- /dev/null +++ b/hw2/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/hw3/code/Assignment3.iml b/hw3/code/Assignment3.iml new file mode 100644 index 0000000..1f742ef --- /dev/null +++ b/hw3/code/Assignment3.iml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/hw3/code/src/main/java/ch/usi/inf/ajp22/Album.java b/hw3/code/src/main/java/ch/usi/inf/ajp22/Album.java index 809bb9e..6da28a6 100644 --- a/hw3/code/src/main/java/ch/usi/inf/ajp22/Album.java +++ b/hw3/code/src/main/java/ch/usi/inf/ajp22/Album.java @@ -3,6 +3,7 @@ package ch.usi.inf.ajp22; import java.util.Comparator; import java.util.List; import java.util.Optional; +import java.util.stream.Collectors; public class Album { @@ -44,19 +45,30 @@ public class Album { /** * 3 Points - * TODO: create a public Optional method called "searchLongestSong" that - * return the longest Track in the album. + * create a public Optional method called "searchLongestSong" that + * return the longest Track on the album. * input: void * output: an Optional */ + public Optional searchLongestSong() { + return this.tracks.stream() + .max(Comparator.comparingInt(Track::getLength)); + } /** * 3 Points - * TODO: create a public List method called "orderSongByTitle" that + * create a public List method called "orderSongByTitle" that * return the track list ordered lexicographically using the title field. * input: void * output: a List */ + public List orderSongByTitle() { + // note: we assume lexicographical order requires letter case to be ignored + return this.tracks.stream() + .sorted((a, b) -> String.CASE_INSENSITIVE_ORDER.compare(a.getTitle(), b.getTitle())) + .collect(Collectors.toList()); + } + @Override public String toString() { diff --git a/hw3/code/src/main/java/ch/usi/inf/ajp22/Main.java b/hw3/code/src/main/java/ch/usi/inf/ajp22/Main.java index 3fab808..f9bdb15 100644 --- a/hw3/code/src/main/java/ch/usi/inf/ajp22/Main.java +++ b/hw3/code/src/main/java/ch/usi/inf/ajp22/Main.java @@ -5,136 +5,197 @@ import java.io.FileWriter; import java.io.IOException; import java.time.LocalDate; import java.util.*; -import java.util.function.BiFunction; -import java.util.function.BinaryOperator; -import java.util.function.IntFunction; -import java.util.function.Predicate; +import java.util.function.*; import java.util.stream.Collectors; +import java.util.stream.IntStream; import java.util.stream.Stream; public class Main { /** * 3 Points - * TODO: create a public static Album method called "longestTitle". - * If the maximum is not found throw a RuntimeException. - * input: a list of Album - * output: the Album with the longest title. + * create a public static Album method called "longestTitle". + * If the maximum is not found throw a RuntimeException. + * input: a list of Album + * output: the Album with the longest title. */ + public static Album longestTitle(List albums) { + return albums.stream() + .max(Comparator.comparingDouble(a -> a.getTitle().length())) + .orElseThrow(RuntimeException::new); + } + /** * 4 Points - * TODO: create a public static int method called "sumOfRatingReduce". - * input: an Album instance. - * output: int that is the sum of all the tracks ratings in the album. + * create a public static int method called "sumOfRatingReduce". + * input: an Album instance. + * output: int that is the sum of all the tracks ratings on the album. * Use the method getTracks from the Album class to get the List of tracks. * You MUST use the reduce method, in the variant which takes as input an identity, an accumulator and a combiner. * If possible use method references. */ + public static int sumOfRatingReduce(Album album) { + return album.getTracks().stream() + .map(Track::getLength) + .reduce(0, Integer::sum, Integer::sum); + } /** * 4 Points - * TODO: create a public static int method called "sumOfRatingCollection". - * input: an Album instance. - * output: int that is the sum of all the tracks ratings in the album + * create a public static int method called "sumOfRatingCollection". + * input: an Album instance. + * output: int that is the sum of all the tracks ratings on the album * Use the method getTracks from the Album class to get the List of tracks. * You MUST use one variant of the collect method. If possible use method references. */ + public static int sumOfRatingCollection(Album album) { + //noinspection SimplifyStreamApiCallChains + return album.getTracks().stream().map(Track::getRating) + .collect(Collectors.reducing(0, Integer::sum)); + } + /** * 4 Points - * TODO: create a public static int method called "sumOfRatingMap" - * input: an ch.usi.inf.ajp22.Album instance. - * output: int that is the sum of all the tracks ratings in the album. + * create a public static int method called "sumOfRatingMap" + * input: a ch.usi.inf.ajp22.Album instance. + * output: int that is the sum of all the tracks ratings on the album. * Use the method getTracks from the Album class to get the List of tracks. * You MUST use the mapToInt method. If possible use method references. */ + public static int sumOfRatingMap(Album album) { + return album.getTracks().stream().mapToInt(Track::getRating).sum(); + } /** * 4 Points - * TODO: create a public static Map method called "countTrackOccurrence" - * input: a list of Track - * output: a Map where the key is the track title and the value is, how many times - * the same song occurs in the list. - * Two songs can be considered the same if they have the same title. + * create a public static Map method called "countTrackOccurrence" + * input: a list of Track + * output: a Map where the key is the track title and the value is, how many times + * the same song occurs in the list. + * Two songs can be considered the same if they have the same title. */ + public static Map countTrackOccurrence(List tracks) { + return tracks.stream().collect(Collectors.groupingBy(Track::getTitle, Collectors.counting())); + } /** * 4 Points - * TODO: create a public static Map> method called "groupAlbumByArtist". - * input: a list of Album - * output: a Map> where the key is an Artist and the value is a List of Album which - * this artist had produced. + * create a public static Map> method called "groupAlbumByArtist". + * input: a list of Album + * output: a Map> where the key is an Artist and the value is a List of Album which + * this artist had produced. */ + public static Map> groupAlbumByArtist(List albums) { + return albums.stream().collect(Collectors.groupingBy(Album::getArtist, Collectors.toList())); + } /** * 4 Points - * TODO: create a public static List method called "trackFilteredWithPredicate". - * input: a stream of tracks and a predicate to apply to the track stream. - * output: a List of Track that has been filtered according to the predicate taken as input. + * create a public static List method called "trackFilteredWithPredicate". + * input: a stream of tracks and a predicate to apply to the track stream. + * output: a List of Track that has been filtered according to the predicate taken as input. */ + public static List trackFilteredWithPredicate(Stream tracks, Predicate predicate) { + return tracks.filter(predicate).collect(Collectors.toList()); + } /** * 5 Points - * TODO: create a public static Stream method called getAlbumWithAtLeastNTracks - * input: a list of Album AND an int called "n" - * output: a List where every album in this stream has at least "n" tracks. + * create a public static Stream method called getAlbumWithAtLeastNTracks + * input: a list of Album AND an int called "n" + * output: a List where every album in this stream has at least "n" tracks. */ + public static Stream getAlbumWithAtLeastNTracks(List albums, int n) { + return albums.stream().filter(a -> a.getTracks().size() >= n); + } /** * 5 Points - * TODO: create a public static void method called "printTrackStatistics". - * input: an Album instance + * create a public static void method called "printTrackStatistics". + * input: an Album instance * Print Track Statistics based on the length of the tracks of an album taken as input in the following format: * === - * "Stat for: %s\n", album.getTitle()) + * "Stat for: %s\n", album.getTitle() * "Max: %d\nMin: %d\nAve: %f\n" * === * Use the method getTracks from the Album class to get the List of tracks. * Input: an Album */ + public static void printTrackStatistics(Album album) { + final Supplier tracksStreamSupplier = () -> album.getTracks().stream().mapToInt(Track::getLength); + final Supplier whenZero = () -> { + throw new IllegalArgumentException("Album has no tracks"); + }; + + System.out.printf("===\nStat for: %s\nMax: %d\nMin: %d\nAve: %f\n===\n", + album.getTitle(), + tracksStreamSupplier.get().max().orElseThrow(whenZero), + tracksStreamSupplier.get().min().orElseThrow(whenZero), + tracksStreamSupplier.get().average().orElseThrow(whenZero)); + } /** * 5 Points - * TODO: create a public static String method called "getArtistNameAndNickNameFromAlbum". - * Each author should appear only once. - * input: a list of Album - * output: a String in the following format: - * [artist1.name - artist1.nickname, artist2.name - artist2.nickname, ...] + * create a public static String method called "getArtistNameAndNickNameFromAlbum". + * Each author should appear only once. + * input: a list of Album + * output: a String in the following format: + * [artist1.name - artist1.nickname, artist2.name - artist2.nickname, ...] */ + public static String getArtistNameAndNickNameFromAlbum(List albums) { + return albums.stream().map(Album::getArtist).distinct() + .map(a -> String.format("%s - %s", a.getName(), a.getNickname())) + .collect(Collectors.joining(",", "[", "]")); + } /** * 5 Points - * TODO: create a public Track method called "combineAllTrackInAlbum" - * input: a stream of track - * output: return a new ch.usi.inf.ajp22.Track with the following values: - * title -> "fake title" - * releaseDate -> LocaleDate.now() - * genre -> DISCO - * length -> the sum of all the lengths in the input track stream. - * The pipeline processing must be done in parallel. - * You MUST use the collect method, in the variant which takes as input a supplier, an accumulator and a - * combiner. + * create a public Track method called "combineAllTrackInAlbum" + * input: a stream of track + * output: return a new ch.usi.inf.ajp22.Track with the following values: + * title -> "fake title" + * releaseDate -> LocaleDate.now() + * genre -> DISCO + * length -> the sum of all the lengths in the input track stream. + * The pipeline processing must be done in parallel. + * You MUST use the collect method, in the variant which takes as input a supplier, an accumulator and a + * combiner. */ + public static Track combineAllTrackInAlbum(Stream tracks) { + return tracks.parallel().collect( + () -> new Track("fake title", LocalDate.now(), Track.Genre.DISCO, 0), + (acc, track) -> acc.setLength(acc.getLength() + track.getLength()), + (acc, other) -> acc.setLength(acc.getLength() + other.getLength())); + } /** * 5 Points - * TODO: create a public static Map> method called "groupTrackByArtist". - * input: a list of Album - * output: a Map> where the key is an Artist and the value is a List of Track which - * this artist had produced. + * create a public static Map> method called "groupTrackByArtist". + * input: a list of Album + * output: a Map> where the key is an Artist and the value is a List of Track which + * this artist had produced. */ + public static Map> groupTrackByArtist(List albums) { + return albums.stream().collect( + Collectors.groupingBy( + Album::getArtist, + Collectors.flatMapping(a -> a.getTracks().stream(), Collectors.toList()))); + } /** * 5 Bonus Points - * TODO: create a public static T[] method called "createArray". - * This method must create a generic array where the elements are in the same order as in the - * input Collection. - * In this function you need neither streams nor lambda. - * input: a Collection and an IntFunction - * output: an array of generic type + * create a public static T[] method called "createArray". + * This method must create a generic array where the elements are in the same order as in the + * input Collection. + * In this function you need neither streams nor lambda. + * input: a Collection and an IntFunction + * output: an array of generic type */ - + public static T[] createArray(Collection collection, IntFunction generator) { + return collection.toArray(generator); + } private static void writeToFile(String s) throws IOException { BufferedWriter fw = new BufferedWriter(new FileWriter("artist.txt", true)); @@ -145,46 +206,51 @@ public class Main { public static void main(String[] args) { Random random = new Random(); - /** + /* * Initializing some SampleData */ SampleData.appetiteForDestruction - .getTracks().forEach(track -> + .getTracks().forEach(track -> track.setRating(random.nextInt(5))); SampleData.randomAccessMemories - .getTracks().forEach(track -> + .getTracks().forEach(track -> track.setRating(random.nextInt(5))); - /** + /* * 2 Points - * TODO: Replace the Anonymous class below with a lambda expression. + * Replace the Anonymous class below with a lambda expression. */ - BinaryOperator mixTrack = new BinaryOperator<>() { - @Override - public Track apply(Track t1, Track t2) { - return new Track(t1.getTitle(), - t1.getReleasedDate(), - t2.getGenre(), - t2.getLength()); - } - }; + BinaryOperator mixTrack = (t1, t2) -> new Track(t1.getTitle(), + t1.getReleasedDate(), + t2.getGenre(), + t2.getLength()); - /** + /* * 3 Points - * TODO: Create a stream pipeline that: + * Create a stream pipeline that: * 1) filter all the tracks that have at least 4 as rating * 2) sort the filtered tracks using the title field * 3) print the tracks */ + SampleData.getShuffledTrack().stream().filter(t -> t.getRating() >= 4) + .sorted(Comparator.comparing(Track::getTitle)) + .forEach(System.out::println); - /** + /* * 4 Points - * TODO: Print on file the artist's name, obtained with the method SampleData.getArtistList(), + * Print on file the artist's name, obtained with the method SampleData.getArtistList(), * using the writeToFile method. Use a lambda expression and handle * the throw exception from the writeToFile method. If there is an IOException you must throw a * RuntimeException with the same event. */ + SampleData.getArtistList().stream().map(Artist::getName).forEach(n -> { + try { + writeToFile(n); + } catch (final IOException e) { + throw new RuntimeException(e); + } + }); System.out.printf("Longest track in %s is %s\n", SampleData.appetiteForDestruction.getTitle(), @@ -229,13 +295,13 @@ public class Main { Map> artistListMap1 = groupTrackByArtist(SampleData.getAlbumList()); for (Map.Entry> entry : artistListMap1.entrySet()) { System.out.println("ch.usi.inf.ajp22.Artist: " + entry.getKey().getName()); - for (Track track: entry.getValue()) { + for (Track track : entry.getValue()) { System.out.println("\t" + track.toString()); } } List trackPOPinGuns = trackFilteredWithPredicate(SampleData.appetiteForDestruction.getTracks().stream() - ,(t -> !t.getGenre().equals(Track.Genre.HIP_HOP))); + , (t -> !t.getGenre().equals(Track.Genre.HIP_HOP))); trackPOPinGuns .forEach(System.out::println); diff --git a/hw3/code/target/classes/ch/usi/inf/ajp22/Album.class b/hw3/code/target/classes/ch/usi/inf/ajp22/Album.class new file mode 100644 index 0000000..cdae949 Binary files /dev/null and b/hw3/code/target/classes/ch/usi/inf/ajp22/Album.class differ diff --git a/hw3/code/target/classes/ch/usi/inf/ajp22/Artist.class b/hw3/code/target/classes/ch/usi/inf/ajp22/Artist.class new file mode 100644 index 0000000..59ad5c5 Binary files /dev/null and b/hw3/code/target/classes/ch/usi/inf/ajp22/Artist.class differ diff --git a/hw3/code/target/classes/ch/usi/inf/ajp22/Main.class b/hw3/code/target/classes/ch/usi/inf/ajp22/Main.class new file mode 100644 index 0000000..0a29d31 Binary files /dev/null and b/hw3/code/target/classes/ch/usi/inf/ajp22/Main.class differ diff --git a/hw3/code/target/classes/ch/usi/inf/ajp22/SampleData.class b/hw3/code/target/classes/ch/usi/inf/ajp22/SampleData.class new file mode 100644 index 0000000..9b167e0 Binary files /dev/null and b/hw3/code/target/classes/ch/usi/inf/ajp22/SampleData.class differ diff --git a/hw3/code/target/classes/ch/usi/inf/ajp22/Track$Genre.class b/hw3/code/target/classes/ch/usi/inf/ajp22/Track$Genre.class new file mode 100644 index 0000000..543f53b Binary files /dev/null and b/hw3/code/target/classes/ch/usi/inf/ajp22/Track$Genre.class differ diff --git a/hw3/code/target/classes/ch/usi/inf/ajp22/Track.class b/hw3/code/target/classes/ch/usi/inf/ajp22/Track.class new file mode 100644 index 0000000..731cb12 Binary files /dev/null and b/hw3/code/target/classes/ch/usi/inf/ajp22/Track.class differ