允许重复的TreeSet或TreeMap

时间:2014-03-07 13:44:54

标签: java collections treemap treeset

我需要一个Collection来排序元素,但不会删除重复项。

我选择了TreeSet,因为TreeSet实际上将值添加到了支持的TreeMap

public boolean add(E e) {
    return m.put(e, PRESENT)==null;
}

TreeMap使用Comparators compare逻辑

删除重复项

我写了Comparator,如果元素相等,则返回1而不是0。因此,在具有相同元素的情况下,具有此TreeSet的{​​{1}}将不会覆盖副本,只会对其进行排序。

我已经针对简单的Comparator对象测试了它,但我需要一组自定义对象。

String

这种方法是否正常或是否有更好的方法来实现这一目标?

修改

实际上我有一个以下类的ArrayList:

public static void main(String[] args)
{       
        List<String> strList = Arrays.asList( new String[]{"d","b","c","z","s","b","d","a"} );      
        Set<String> strSet = new TreeSet<String>(new StringComparator());       
        strSet.addAll(strList);     
        System.out.println(strSet); 
}

class StringComparator implements Comparator<String>
{
    @Override
    public int compare(String s1, String s2)
    {
        if(s1.compareTo(s2) == 0){
            return 1;
        }
        else{
            return s1.compareTo(s2);
        }
    }
}

我需要class Fund { String fundCode; BigDecimal fundValue; ..... public boolean equals(Object obj) { // uses fundCode for equality } } 最高fundCode

的所有fundValue

7 个答案:

答案 0 :(得分:4)

  

我需要所有具有最高fundValue的fundCode

如果这是您想要排序的唯一原因,我建议不要排序。排序主要是复杂的 O(n log(n))。找到最大值只有 O(n)的复杂性,并在列表上的简单迭代中实现:

List<Fund> maxFunds = new ArrayList<Fund>();
int max = 0;
for (Fund fund : funds) {
    if (fund.getFundValue() > max) {
        maxFunds.clear();
        max = fund.getFundValue();

    }
    if (fund.getFundValue() == max) {
        maxFunds.add(fund);

    }
}

您可以使用第三级库(例如Guava)来避免该代码。请参阅:How to get max() element from List in Guava

答案 1 :(得分:3)

您可以使用Collections.sort对列表进行排序。

给出Fund

List<Fund> sortMe = new ArrayList(...);
Collections.sort(sortMe, new Comparator<Fund>() {
  @Override
  public int compare(Fund left, Fund right) {
    return left.fundValue.compareTo(right.fundValue);
  }
});
// sortMe is now sorted

答案 2 :(得分:1)

您可以使用PriorityQueue。

PriorityQueue<Integer> pQueue = 

               new PriorityQueue<Integer>(); 

PriorityQueue():创建一个具有默认初始容量(11)的PriorityQueue,该初始容量根据其自然顺序对元素进行排序。

答案 3 :(得分:0)

对于TreeSet,Comparator或Comparable用于比较和存储对象。不调用等于,这就是为什么它不能识别重复的

答案 4 :(得分:0)

我们可以使用List并实现Comparable接口,而不是TreeSet。

public class Fund implements Comparable<Fund> {

    String fundCode;
    int fundValue;

    public Fund(String fundCode, int fundValue) {
        super();
        this.fundCode = fundCode;
        this.fundValue = fundValue;
    }

    public String getFundCode() {
        return fundCode;
    }

    public void setFundCode(String fundCode) {
        this.fundCode = fundCode;
    }

    public int getFundValue() {
        return fundValue;
    }

    public void setFundValue(int fundValue) {
        this.fundValue = fundValue;
    }

    public int compareTo(Fund compareFund) {

        int compare = ((Fund) compareFund).getFundValue();
        return compare - this.fundValue;
    }

    public static void main(String args[]){

        List<Fund> funds = new ArrayList<Fund>();

        Fund fund1 = new Fund("a",100);
        Fund fund2 = new Fund("b",20);
        Fund fund3 = new Fund("c",70);
        Fund fund4 = new Fund("a",100);
        funds.add(fund1);
        funds.add(fund2);
        funds.add(fund3);
        funds.add(fund4);

        Collections.sort(funds);

        for(Fund fund : funds){
            System.out.println("Fund code: " + fund.getFundCode() +  "  Fund value : " + fund.getFundValue());
        }
    }
}

答案 5 :(得分:0)

将元素添加到arraylist,然后使用实用程序Collections.sort对元素进行排序。然后实现可比较,并根据您的密钥编写自己的compareTo方法。

也不会删除重复项,也可以进行排序:

List<Integer> list = new ArrayList<>();

Collections.sort(list,new Comparator<Integer>() 
{

  @Override


  public int compare(List left, List right) {


**your logic**

     return '';

  }

}

)
;

答案 6 :(得分:0)

我找到了一种方法来获取TreeSet来存储重复的密钥。

当我使用SortedContainers在python中编写一些代码时,就会出现问题。我有一个对象的空间索引,我想在其中查找开始/结束经度之间的所有对象。

经度可以重复,但我仍然需要能够从索引中有效添加/删除特定对象的功能。不幸的是,我找不到与Python SortedKeyList等效的Java,它可以将排序键与要存储的类型分开。

为说明这一点,请考虑我们有大量的零售购买清单,并且希望获得成本在特定范围内的所有购买。

// We are using TreeSet as a SortedList
TreeSet _index = new TreeSet<PriceBase>()

// populate the index with the purchases. 
// Note that 2 of these have the same cost
_index.add(new Purchase("candy", 1.03));
Purchase _bananas = new Purchase("bananas", 1.45);
_index.add(new Purchase(_bananas);
_index.add(new Purchase("celery", 1.45));
_index.add(new Purchase("chicken", 4.99));

// Range scan. This iterator should return "candy", "bananas", "celery"
NavigableSet<PriceBase> _iterator = _index.subset(
    new PriceKey(0.99), new PriceKey(3.99));

// we can also remove specific items from the list and
// it finds the specific object even through the sort
// key is the same
_index.remove(_bananas);

为该列表创建了3个类

  • PriceBase:返回排序键(价格)的基类。
  • 购买:包含交易数据的子类。
  • PriceKey:用于范围搜索的子类。

当我最初使用TreeSet实现此功能时,除了价格相同的情况外,它都起作用。诀窍是定义compareTo()以使其具有多态性:

  1. 如果我们将“购买”与“价格关键字”进行比较,则仅比较价格。
  2. 如果我们将“购买与购买”进行比较,则在价格相同的情况下比较价格和名称。

例如,这里是PriceBase和Purchase类的compareTo()函数。

// in PriceBase
@Override
public int compareTo(PriceBase _other) {
    return Double.compare(this.getPrice(), _other.getPrice());
}

// in Purchase
@Override
public int compareTo(PriceBase _other) {

    // compare by price
    int _compare = super.compareTo(_other);

    if(_compare != 0) {
        // prices are not equal
        return _compare;
    }

    if(_other instanceof Purchase == false) {
        throw new RuntimeException("Right compare must be a Purchase");
    }

    // compare by item name
    Purchase _otherPurchase = (Purchase)_other;
    return this.getName().compareTo(_otherChild.getName());
}

此技巧使TreeSet可以按价格对购买进行排序,但是当需要唯一标识一个时,仍然可以进行真实的比较。

总而言之,我需要一个对象索引来支持范围扫描,其中键是连续值(例如double),并且添加/删除非常有效。

我知道还有很多其他方法可以解决此问题,但我想避免编写自己的树类。我的解决方案看起来像是骇客,令我惊讶的是我找不到其他东西。如果您知道更好的方法,请发表评论。

相关问题