package MusicLandscape.container;
import MusicLandscape.entities.Track;
import MusicLandscape.util.MyMatcher;
import java.util.*;package MusicLandscape.container;
import MusicLandscape.entities.Track;
import MusicLandscape.util.MyMatcher;
import java.util.*;The interesting things here are:
List<T> for our selection, I chose ArrayListSet<T> for our tracks, I chose HashSetMyMatcher<Track>Comparator<Track>/**
* Represents a set of tracks and a (possibly empty) subset of those tracks which are selected.
* <p>
* This class is a container for unique tracks. It does not accept null tracks, nor can a track which is already
* contained be added again. Additionally, it supports the notion of selection, meaning that some tracks can be
* selected. The selection is a subset of all tracks currently held by the container. The selection may at times be
* empty, and it may at other times contain all tracks.
* <p>
* The container provides methods to filter, sort, and retrieve the selection.
* <p>
* Tracks can only be removed from this container by removing all currently selected tracks. Removing tracks therefore
* requires the creation of a proper selection first. The usual process of creating a selection is:
*
* <ol>
* <li>select ALL tracks (by resetting the selection)</li>
* <li>(possibly repeatedly) filter the selection with a matcher. The filter is applied to the current selection!</li>
* <li>if desired, sort the selection.</li>
* <li>remove selected tracks from container OR retrieve the selection as an array of tracks.</li>
* </ol>
*
* @author Jonas Altrock (ew20b126@technikum-wien.at)
* @version 1
* @since ExerciseSheet05
*/
public class MyTrackContainer {
/**
* The selected tracks in this container.
* Initially empty.
*/
private final List<Track> selection = new ArrayList<>();
/**
* The tracks in this container.
* Initially empty.
*/
private final Set<Track> tracks = new HashSet<>();
/**
* Creates a default MyTrackContainer.<br>
* A default container has no tracks and an empty selection.
*/
public MyTrackContainer() {
}An object that implements Iterable<T> can be used in an enhanced for loop.
/**
* Creates a container from an iterable object of tracks.<br>
* All tracks of the argument are added to this container.
* <p>
* Initially, all tracks are selected.
*
* @param t the iterable object of tracks to be added to this container.
*/
public MyTrackContainer(Iterable<Track> t) {
for (Track track : t) {
tracks.add(track);
selection.add(track);
}
}
/**
* Creates a container from an array of tracks.<br>
* All tracks of the argument are added to this container.
* <p>
* Initially, all tracks are selected.
*
* @param t the array of tracks to be added to this container.
*/
public MyTrackContainer(Track[] t) {
this(List.of(t));
}
/**
* Add a single track.<br>
* The argument is attempted to be added to this container.
* <p>
* If successfully added, it is NOT added to the selection. Tracks already added cannot be added again.
* Null tracks cannot be added either.
*
* @param t the track to add
* @return whether the argument could be added
*/
public boolean add(Track t) {
if (t == null) {
return false;
}
if (tracks.contains(t)) {
return false;
}
tracks.add(t);
return true;
}
/**
* Bulk operation to add tracks.<br>
* All tracks of the argument are added to this container.
*
* @param t the tracks to add
* @return the number of tracks added
*/
public int addAll(Track[] t) {
int added = 0;
for (Track track : t) {
if (add(track)) {
added++;
}
}
return added;
}
/**
* Filters the selection.<br>
* Applies the filter defined by the argument to the selection, keeping only those elements that match.
* <p>
* The filter is applied to the selection and the selection only, i.e. the selection cannot grow in size during
* this operation. If all elements of a selection match the specified filter, the selection remains unchanged.
*
* @param matcher the filter defining which of the tracks of the selection to keep.
* @return the number of elements removed from the selection during this operation.
*/
public int filter(MyMatcher<Track> matcher) {
int removed = 0;Here we see the other style of using an Iterable<T>. A List<T> is Iterable, which
means we can get an Iterator from it, which can produce new values via .next(),
or, as we can see here, modify the iterable collection with .remove().
for (Iterator<Track> it = selection.iterator(); it.hasNext(); ) {
Track t = it.next();
if (!matcher.matches(t)) {
it.remove();
removed++;
}
}
return removed;
}
/**
* Removes the selected tracks from this container.<br>
* All currently selected tracks are removed from this container.
* <p>
* After this operation all remaining tracks are selected (the selection is reset).
*
* @return the number of removed tracks
*/
public int remove() {
int removed = selection.size();
for (Track track : selection) {
tracks.remove(track);
}
reset();
return removed;
}
/**
* Resets the selection, thereby selecting ALL tracks in this container.
*/
public void reset() {
selection.retainAll(List.<Track>of());
selection.addAll(tracks);
}
/**
* Gets the selected tacks.<br>
* The currently selected tracks of this container are returned as an array of tracks.
* <p>
* The tracks are returned in their current order.
* If the selection is empty an array of size 0 is returned.
*
* @return the selected tracks.
*/
public Track[] selection() {
return selection.toArray(new Track[0]);
}
/**
* The number of tracks currently held by this container.<br>
* Note: this is not the size of the selection.
*
* @return the number of tracks
*/
public int size() {
return tracks.size();
}Sorting can use the built-in sorting algorithm of the Java collections
framework because it builds on the Comparator interface.
Conveniently, there is a .reversed() method to sort the other way.
/**
* Sorts the selection of tracks of this container.<br>
* The currently selected tracks are sorted in the sense defined by the first argument.
* <p>
* The second argument controls the scheme (ascending/descending order).
*
* @param theComp the comparator defining the sorting order
* @param asc the sorting scheme. true stands for ascending (from smallest to highest element) false for descending.
*/
public void sort(Comparator<Track> theComp, boolean asc) {
selection.sort(asc ? theComp : theComp.reversed());
}
}