A TreeSet or TreeMap that allow duplicates

前端 未结 7 1693
走了就别回头了
走了就别回头了 2021-01-17 23:12

I need a Collection that sorts the element, but does not removes the duplicates.

I have gone for a TreeSet, since TreeSet actu

相关标签:
7条回答
  • 2021-01-17 23:51

    In case of TreeSet either Comparator or Comparable is used to compare and store objects . Equals are not called and that is why it does not recognize the duplicate one

    0 讨论(0)
  • 2021-01-17 23:53

    you can sort a List using Collections.sort.

    given your 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
    
    0 讨论(0)
  • 2021-01-18 00:00

    I need all the fundCode with highest fundValue

    If that's the only reason why you want to sort I would recommend not to sort at all. Sorting comes mostly with a complexity of O(n log(n)). Finding the maximum has only a complexity of O(n) and is implemented in a simple iteration over your list:

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

    You can avoid that code by using a third level library like Guava. See: How to get max() element from List in Guava

    0 讨论(0)
  • 2021-01-18 00:00

    You can use a PriorityQueue.

    PriorityQueue<Integer> pQueue = new PriorityQueue<Integer>(); 
    

    PriorityQueue(): Creates a PriorityQueue with the default initial capacity (11) that orders its elements according to their natural ordering.

    This is a link to doc: https://docs.oracle.com/javase/8/docs/api/java/util/PriorityQueue.html

    0 讨论(0)
  • 2021-01-18 00:03

    Instead of the TreeSet we can use List and implement the Comparable interface.

    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());
            }
        }
    }
    
    0 讨论(0)
  • 2021-01-18 00:08

    I found a way to get TreeSet to store duplicate keys.

    The problem originated when I wrote some code in python using SortedContainers. I have a spatial index of objects where I want to find all objects between a start/end longitude.

    The longitudes could be duplicates but I still need the ability to efficiently add/remove specific objects from the index. Unfortunately I could not find the Java equivalent of the Python SortedKeyList that separates the sort key from the type being stored.

    To illustrate this consider that we have a large list of retail purchases and we want to get all purchases where the cost is in a specific range.

    // 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);
    

    There are 3 classes created for the list

    • PriceBase: Base class that returns the sort key (the price).
    • Purchase: subclass that contains transaction data.
    • PriceKey: subclass used for the range search.

    When I initially implemented this with TreeSet it worked except in the case where the prices are the same. The trick is to define the compareTo() so that it is polymorphic:

    1. If we are comparing Purchase to PriceKey then only compare the price.
    2. If we are comparing Purchase to Purchase then compare the price and the name if the prices are the same.

    For example here are the compareTo() functions for the PriceBase and Purchase classes.

    // 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());
    }
    

    This trick allows the TreeSet to sort the purchases by price but still do a real comparison when one needs to be uniquely identified.

    In summary I needed an object index to support a range scan where the key is a continuous value like double and add/remove is efficient.

    I understand there are many other ways to solve this problem but I wanted to avoid writing my own tree class. My solution seems like a hack and I am surprised that I can't find anything else. if you know of a better way then please comment.

    0 讨论(0)
提交回复
热议问题