簡體   English   中英

按一個值對java對象集合進行排序,並由另一個值保持唯一

[英]Sort a java collection of objects by one value and remain unique by another value

我需要通過Integer值“level”對對象的java集合進行排序。 我還需要通過“title”確定此集合是否已包含對象。

我相信集合的最佳選擇是TreeSet具有一組有序的唯一值。

我有一個帶有“級別”和“標題屬性的對象。它實現了類似的可比性:

它會覆蓋Equals方法(用於檢查對象是否已通過“title”包含在TreeSet中)。

代碼如下:

@Override
public boolean equals(Object arg0) {

    Artifact obj = (Artifact) arg0;

    if (this.getTitle().equals(obj.getTitle())) { 
        return true;
    }

    return false;
}

@Override
public int compareTo(Artifact aThat) {  

    final int BEFORE = -1;
    final int EQUAL = 0;
    final int AFTER = 1;

    if (this == aThat) return EQUAL;

    if (this.level < aThat.level) return BEFORE;
    if (this.level > aThat.level) return AFTER;

    assert this.equals(aThat) : "compareTo inconsistent with equals.";
    return EQUAL;
}

當我嘗試從可能具有重復值的arraylist向列表中添加值時。 包含似乎不起作用,並且無論如何都將對象添加到TreeSet中。 這是代碼:

TreeSet<Artifact> subsetOfArtifacts = new TreeSet<Artifact>();

ArrayList<Artifact> allArtifacts = getArtifacts(); 
Iterator<Artifact> allArtifactsIter = allArtifacts.iterator();

while (allArtifactsIter.hasNext()) {
    Artifact artifact = (Artifact) allArtifactsIter.next();
    if (!subsetOfArtifacts.contains(artifact)) {
        subsetOfArtifacts.add(artifact);
    }
 }

我希望理想情況下有一個按級別排序的所有唯一工件的列表。 我該如何做到這一點?

如果重寫equals()你也應該覆蓋hashCode() 否則,未定義集合(尤其是集合)的行為。 您應該將此方法添加到您的類:

@Override
public int hashCode() {
    return title.hashCode();
}

接下來,您應該使用HashSet而使用Set sortedSet = new TreeSet(set); 用於分類。 一旦你這樣做,它應該都可以正常工作。

原因是HashTables依賴的事實是,如果兩個對象equal()那么它們的hashCode() 也是相等的。 這是來自hashCode()的javadoc的摘錄

hashCode的一般契約是:

  • 每當在執行Java應用程序期間多次在同一對象上調用它時,hashCode方法必須始終返回相同的整數,前提是不修改對象的equals比較中使用的信息。 從應用程序的一次執行到同一應用程序的另一次執行,該整數不需要保持一致。
  • 如果兩個對象根據equals(Object)方法相等,則對兩個對象中的每一個調用hashCode方法必須生成相同的整數結果。
  • 如果兩個對象根據equals(java.lang.Object)方法不相等,則不需要在兩個對象中的每一個上調用hashCode方法必須生成不同的整數結果。 但是,程序員應該知道為不等對象生成不同的整數結果可能會提高哈希表的性能。

您不僅需要compareTo來比較級別,還需要它來比較標題,因為equals比較標題。

public int compareTo(Artifact aThat) {

    final int BEFORE = -1;
    final int EQUAL = 0;
    final int AFTER = 1;

    if ( this == aThat ) return EQUAL;

    if (this.level < aThat.level) return BEFORE;
    if (this.level > aThat.level) return AFTER;
    return this.getTitle().compareTo(aThat.getTitle());

//        assert this.equals(aThat) : "compareTo inconsistent with equals.";

//    return EQUAL;
}

另外,正如波希米亞人所提到的,如果你要覆蓋equals(),你應該覆蓋hashCode(),但這不是你的TreeSet允許你添加重復項的原因。

RTFM:TreeSet的D javadoc明確指出:“注意,如果要正確實現Set接口,則由一個集合維護的排序(無論是否提供顯式比較器)必須與equals一致”

你的等於和比較器是不一致的。 你需要添加的那個,然后你必須對它進行排序。

您可能需要為您的用例創建自己的實現

正如其他人所說:如果改變等號,總是改變哈希碼。

2個相等的對象必須產生相同的哈希碼。

你的compareTo應首先檢查級別,然后檢查標題,如果你想先按級別然后按標題排序,只有當級別和標題相等時才返回相等。 像這樣的東西:

@Override
public int compareTo(Artifact aThat) 
{
    final int BEFORE = -1;
    final int EQUAL = 0;
    final int AFTER = 1;

    if ( this == aThat ) return EQUAL;

    if( this.level < aThat.level ) return BEFORE;
    if( this.level > aThat.level ) return AFTER;

    int compare = this.getTitle().compareTo(aThat.getTitle());

    if( compare != EQUAL ) return compare;

    assert this.equals(aThat) : "compareTo inconsistent with equals.";

    return EQUAL;
}

張貼之前沒有看到搶劫的回答。

暫無
暫無

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

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