Сортировка и различение элементов в наборе деревьев с различными критериями - PullRequest
0 голосов
/ 28 февраля 2020

Extreme Java newb ie здесь. Я делаю несколько простых упражнений, чтобы немного попрактиковаться с базовыми c концепциями языка.

В одном из этих упражнений мне предлагается реализовать класс MusicAlbum, который, среди прочего, имеет один его экземпляров атрибутов - список экземпляров класса MusicTrack.

Поскольку каждый MusicTrack должен быть уникально идентифицирован по его идентификатору, и с учетом того, что указано, что указанный список должен быть «отсортирован» (хотя нет реального указания на это), я выбрал TreeSet.

Так что я реализовал Comparable в классе MusicTrack, чтобы набор MusicAlbum был отсортирован по идентификаторам экземпляров MusicTrack, которые он содержит. Кроме того, два экземпляра MusicTrack с одинаковым идентификатором будут считаться одним и тем же экземпляром MusicTrack, и в дереве не будет дубликатов. Пока все хорошо (или, по крайней мере, я так думаю).

Проблема возникает, когда упражнение просит сделать класс MusicAlbum повторяемым в порядке убывания продолжительности (что является еще одним атрибутом класс MusicTrack).

Я сразу подумал изменить метод CompareTo, чтобы сортировка набора деревьев вместо этого была организована по длительности, в то время как переопределение метода equals класса Object по-прежнему гарантировало бы уникальность Я бы. Тем не менее, это не сработало, похоже, что существование метода CompareTo делает метод equals совершенно неуместным.

Итак, вот мой вопрос: можно ли отсортировать набор деревьев по критериям и сохранить уникальность в этом тот же набор деревьев с совершенно другими критериями?

Я нашел эту цитату, которая может предположить, что такая вещь, если вообще возможно, все еще не рекомендуется:

Обратите внимание, что порядок поддерживается по отсортированной карте (независимо от того, предоставлен или нет явный компаратор) должен быть согласован с equals, если эта отсортированная карта должна правильно реализовывать интерфейс Map. (См. Comparable или Comparator для точного определения соответствия с equals.) Это так, потому что интерфейс Map определен в терминах операции equals, но карта выполняет все ключевые сравнения, используя свой метод CompareTo (или сравнение), поэтому два ключа которые считаются равными этим методом, с точки зрения отсортированной карты равны. Поведение отсортированной карты четко определено, даже если ее порядок не совпадает с равенством; он просто не соблюдает общий контракт интерфейса Map.

Однако информация, которую я нашел по этому поводу, меня довольно смущает, поэтому я прошу разъяснений.

Также, что может быть хорошим способом решить это упражнение? Конечно, вот что мне удалось сделать до сих пор:

MusicTrack. java

public class MusicTrack implements Comparable<MusicTrack> {

    private static int nextId = 0;

    private int id;
    private String title;
    private String author;
    private int duration;

    @SuppressWarnings("serial")
    public class NegativeDurationException extends Exception {

        public NegativeDurationException() {

            System.err.println("Duration value must be greater than 0.");
        }
    }

    public MusicTrack(String title, String author, int duration) throws NegativeDurationException {

        if(duration < 1) {

            throw new NegativeDurationException();
        }
        else {

            this.id = nextId++;
            this.title = title;
            this.author = author;
            this.duration = duration;
        }
    }

    public int getId() {

        return this.id;
    }

    public String getTitle() {

        return this.title;
    }

    public void setTitle(String title) {

        this.title = title;
    }

    public String getAuthor() {

        return this.author;
    }

    public void setAuthor(String author) {

        this.author = author;
    }

    public int getDuration() {

        return this.duration;
    }

    public void setDuration(int duration) {

        this.duration = duration;
    }

    public String toString() {

        return "Id: " + this.id  + "\nAuthor: " + this.author + "\nTitle: " + this.title + "\nDuration: " + this.duration + "\n";
    }

    @Override
    public int compareTo(MusicTrack track) {

        return this.id - track.id;
    }
}

MusicAlbum. java

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Iterator;
import java.util.Set;
import java.util.TreeSet;

public class MusicAlbum implements Iterable<MusicTrack> {

    public enum PhysicalMedia {

        VYNIL, CD, USB
    }

    private static int nextId = 0;

    private int id;
    private String title;
    private String author;
    private Date purchaseTime;
    private Set<MusicTrack> tracks;
    private PhysicalMedia physicalMedia;

    public MusicAlbum(String title, String author, String purchaseTime, PhysicalMedia physicalMedia) {

        try {

            this.purchaseTime = new SimpleDateFormat("dd/mm/yyyy").parse(purchaseTime);
        } 
        catch (ParseException e) {

            e.printStackTrace();
        }

        this.id = nextId++;
        this.title = title;
        this.author = author;
        this.physicalMedia = physicalMedia;
        this.tracks = new TreeSet<MusicTrack>();
    }

    public void addMusicTracks(MusicTrack ... tracks) {

        for(MusicTrack track: tracks) {

            this.tracks.add(track);
        }
    }

    public boolean contains(MusicTrack track) {

        return this.tracks.contains(track);
    }

    public int getTotalDuration() {

        Iterator<MusicTrack> i = this.tracks.iterator();
        int totalDuration = 0;

        while(i.hasNext()) {

            totalDuration += i.next().getDuration();
        }

        return totalDuration;
    }

    public String toString() {

        return "Id: " + this.id + "\nDate: " + this.purchaseTime.toString() + "\nTotal duration: " + this.getTotalDuration();
    }


    @Override
    public Iterator<MusicTrack> iterator() {

        return this.tracks.iterator();
    }

}

1 Ответ

3 голосов
/ 28 февраля 2020
  1. Запись длительности компаратор.
class DurationComparator implements Comparator<MusicTrack> {

    @Override
    public int compare(MusicTrack o1, MusicTrack o2) {
        int d1 = o1 == null ? 0 : o1.getDuration();
        int d2 = o2 == null ? 0 : o2.getDuration();
        return d2 - d1;
    }
}
Изменение метода iterator() в классе MusicAlbum
public Iterator<MusicTrack> iterator() {
    TreeSet<MusicTrack> temp = new TreeSet<MusicTrack>(new DurationComparator());
    temp.addAll(tracks);
    return temp.iterator();
}

Теперь итератор выводит список дорожек в порядке уменьшения продолжительности, тогда как простой вывод списка дорожек отображает их в порядке идентификатора.

Демонстрация кода.
(Обратите внимание, что я добавил метод getTracks() в класс MusicAlbum, который возвращает tracks член.)

public static void main(String[] args) throws NegativeDurationException {
    MusicAlbum album = new MusicAlbum("title", "author", "03/10/2003", PhysicalMedia.CD);
    MusicTrack track1 = new MusicTrack("title_1", "author_1", 30);
    MusicTrack track2 = new MusicTrack("title_2", "author_2", 40);
    MusicTrack track3 = new MusicTrack("title_3", "author_3", 10);
    MusicTrack track4 = new MusicTrack("title_4", "author_4", 20);
    album.addMusicTracks(track1, track2, track3, track4);
    Iterator<MusicTrack> iter = album.iterator();
    while (iter.hasNext()) {
        System.out.println(iter.next());
    }
    System.out.println("====================================================================");
    album.getTracks().forEach(System.out::println);
}

Вывод указанного выше main() метода:

Id: 1
Author: author_2
Title: title_2
Duration: 40

Id: 0
Author: author_1
Title: title_1
Duration: 30

Id: 3
Author: author_4
Title: title_4
Duration: 20

Id: 2
Author: author_3
Title: title_3
Duration: 10

====================================================================
Id: 0
Author: author_1
Title: title_1
Duration: 30

Id: 1
Author: author_2
Title: title_2
Duration: 40

Id: 2
Author: author_3
Title: title_3
Duration: 10

Id: 3
Author: author_4
Title: title_4
Duration: 20

РЕДАКТИРОВАТЬ

Из-за вашего комментария, @Gian, я понимаю, что вам нужен список итератор, а не набор , потому что там может быть два или более MusicTrack с с одинаковой продолжительностью. Следовательно, метод iterator() в классе MusicAlbum становится:

public Iterator<MusicTrack> iterator() {
    List<MusicTrack> temp = new ArrayList<MusicTrack>();
    temp.addAll(tracks);
    Collections.sort(temp, new DurationComparator());
    return temp.iterator();
}

Теперь посмотрим, что произойдет, когда вы перечисляете дорожки альбома, в которых два или более дорожек имеют одинаковую длительность.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...