簡體   English   中英

使用不同的標准對樹集中的元素進行排序和區分

[英]Sorting and distinguishing elements within a treeset with different criterias

這里是極限 Java 新手。 我正在做一些簡單的練習,以便對語言的基本概念進行一些練習。

其中一個練習要求我實現一個 MusicAlbum 類,它的實例屬性之一是類 MusicTrack 的實例列表。

由於每個 MusicTrack 必須由其 id 唯一標識,並且考慮到指定所述列表必須“排序”(盡管沒有真正的指示),我選擇了 TreeSet。

因此,我在 MusicTrack 類中實現了 Comparable,以便 MusicAlbum 的集合將按其包含的 MusicTrack 實例的 id 進行排序。 此外,兩個具有相同 id 的 MusicTrack 實例將被視為相同的 MusicTrack 實例,然后樹集中不會有重復項。 到目前為止一切順利(或者至少我是這么認為的)。

當練習要求按持續時間遞減的順序(這是 MusicTrack 類的另一個屬性)使 MusicAlbum 類可迭代時,就會出現問題。

我立即想到修改 compareTo 方法,以便樹集的排序改為按持續時間組織,而重寫 Object 類的 equals 方法仍將保證按 id 的唯一性。 但是,這不起作用,似乎 compareTo 方法的存在使 equals 方法完全無關緊要。

所以這是我的問題:是否可以使用標准對樹集進行排序,並使用完全不同的標准在同一樹集中保持唯一性?

我發現這句話可能表明,即使可能,仍然不建議這樣做:

請注意,如果排序映射要正確實現 Map 接口,則排序映射(無論是否提供顯式比較器)維護的順序必須與 equals 一致。 (請參閱 Comparable 或 Comparator 以獲得與等於一致的精確定義。)這是因為 Map 接口是根據等於操作定義的,但映射使用其 compareTo(或比較)方法執行所有鍵比較,因此兩個鍵從排序映射的角度來看,被這種方法視為相等的對象是相等的。 排序映射的行為是明確定義的,即使它的排序與 equals 不一致; 它只是不遵守 Map 接口的一般約定。

然而,我發現的有關這方面的信息對我來說很困惑,所以我要求澄清。

還有什么是解決這個練習的好方法? 當然,這是我目前設法做到的:

音樂曲目

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;
    }
}

音樂專輯.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. 寫一個持續時間比較器。
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;
    }
}
  1. 更改類MusicAlbum方法iterator()
public Iterator<MusicTrack> iterator() {
    TreeSet<MusicTrack> temp = new TreeSet<MusicTrack>(new DurationComparator());
    temp.addAll(tracks);
    return temp.iterator();
}

現在迭代器按持續時間遞減的順序列出曲目,而簡單地列出曲目按 ID 的順序顯示它們。

演示代碼。
(請注意,我將方法getTracks()添加到返回tracks成員的MusicAlbum類。)

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具有相同的持續時間。 因此,類MusicAlbum方法iterator()變為:

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

現在看看當您列出專輯中兩首或多首曲目具有相同持續時間的曲目時會發生什么。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM