jaewhyun
jaewhyun

Reputation: 69

TreeMap Key, Value pair exists, but .get(Key) returns the value as null

I have this code (below) that when I print the treemap, I can clearly see the key,value pairs. Every key has a value (no null values in the output). When I get the first key, it will give me the key, but when I try to get the value based on the key, it will return null.

TreeMap<String, Double> cosinesimilarityvalues = simvalfordoc.returnsortedcosinesimilarityvalues();
System.out.println(cosinesimilarityvalues);
String topkey = cosinesimilarityvalues.firstKey();      
System.out.println(topkey);
Double topvalue = cosinesimilarityvalues.get(topkey);
System.out.println(topvalue);
topones.put(topkey, topvalue);

Here is part of an output :

{article04_C9,article08_C12=0.0, article04_C9,article18_C10=0.0, article04_C9,article07_C1=0.0, article04_C9,article03_C10=0.0, article04_C9,article01_C10=0.0, article04_C9,article07_C10=0.0, article04_C9,article17_C10=0.0, article04_C9,article10_C10=0.0, article04_C9,article05_C10=0.0, article04_C9,article11_C10=0.0, article04_C9,article02_C10=0.0, article04_C9,article13_C10=0.0, article04_C9,article02_C13=5.676594773265355E-4, article04_C9,article02_C11=6.228132014119322E-4, article04_C9,article06_C10=6.732460014209593E-4, article04_C9,article12_C10=0.0011438670619737105, article04_C9,article03_C3=0.0011907203907551985, article04_C9,article03_C11=0.0012323612320990097}

So I should be getting article04_C9,article08_C12 as firstKey() (which I do) but when I go to retrieve the value associated with that key, it returns null.

Here is the code that I'm using to populate the treemap

HashMap<String, Double> cosinesimilarityvalues = new HashMap<String, Double>();
TreeMap<String, Double> sortedcosinesimilarityvalues = new TreeMap<String, Double>();
public void comparecosinesimilarityvalues(List<tfidfvalues> matrix, tfidfvalues currentvector) {
    String articlename = currentvector.returnarticlename();
    String foldername = currentvector.returnfoldername();
    ArrayList<Double> tfidfval = currentvector.returntfidfvaluesforrow();
    articlefolder = articlename+ "_" + foldername;
    CosineSimilarity calculator = new CosineSimilarity();
    for(int i = 0; i < matrix.size(); i++) {
        String compvectorarticlename = matrix.get(i).returnarticlename();
        String compvectorfoldername = matrix.get(i).returnfoldername();
        ArrayList<Double> compvector = matrix.get(i).returntfidfvaluesforrow();

        Double cosinesimilarity = calculator.CosineSimilarityCalc(tfidfval, compvector);

        String comparingwhat = compvectorarticlename + "_" + compvectorfoldername;

        String comparingthese = articlefolder + "," + comparingwhat;
        cosinesimilarityvalues.put(comparingthese, cosinesimilarity);
    }

    Iterator<Map.Entry<String, Double>> iterator = cosinesimilarityvalues.entrySet().iterator();
    while(iterator.hasNext()) {
        Map.Entry<String, Double> entry = iterator.next();
        if((entry.getValue() > 0.989 && entry.getValue() < 1) || entry.getValue() > 1) {
            iterator.remove();
        }
    }

    sortedcosinesimilarityvalues = sortMapByValue(cosinesimilarityvalues);
}

public TreeMap<String, Double> returnsortedcosinesimilarityvalues() {
    return sortedcosinesimilarityvalues;
}

Here is the function I am using to sort by value...if that helps

from : https://www.programcreek.com/2013/03/java-sort-map-by-value/

class ValueComparator implements Comparator<String>{

    HashMap<String, Double> map = new HashMap<String, Double>();

    public ValueComparator(HashMap<String, Double> map){
        this.map.putAll(map);
    }

    @Override
    public int compare(String s1, String s2) {
        if(map.get(s1) >= map.get(s2)){
            return 1;
        }else{
            return -1;
        }   
    }
}

public TreeMap<String, Double> sortMapByValue(HashMap<String, Double> map){
    Comparator<String> comparator = new ValueComparator(map);
    //TreeMap is a map sorted by its keys. 
    //The comparator is used to sort the TreeMap by keys. 
    TreeMap<String, Double> result = new TreeMap<String, Double>(comparator);
    result.putAll(map);
    return result;
}

I'm not sure what I'm doing wrong. Please help!

Thanks!


UPDATE

I was able to retrieve the top key and top value via

Map.Entry<String, Double> entry1 = cosinesimilarityvalues.firstEntry();
String topkey = entry1.getKey();
Double topvalue = entry1.getValue();

but I have no idea why this works and the other method does not work. Although my code now works, I wish I could find out what the difference is!

Upvotes: 2

Views: 2111

Answers (3)

Andrei Socaciu
Andrei Socaciu

Reputation: 1198

Usually a Map starts "misbehaving" if its internal state is inconsistent. With a TreeMap, as in your case, that would be caused by a Comparator which is not stable, meaning it doesn't always return the same result for the same input values.

Not having access to the whole code it's hard to pinpoint the cause, one thing to notice is however that your TreeMap becomes inconsistent if you modify it after the initial creation within the sort method. That's because your comparator relies on the state of the map at the time it's instantiated, any later changes are not seen by the comparator.

The firstKey() and firstEntry() methods don't use the comparator for retrieval, they simply go all the way "left" in the binary tree that backs the TreeMap. However get(key) uses the comparator to find the key in the tree, which in your case does not work correctly.

Another possible cause from this answer to a similar question is that your comparator does not respect the requirement

sgn(compare(x, y)) == -sgn(compare(y, x))

That is, if two entries A and B have the same value, comparing (A,B) with your code yields 1, and comparing (B,A) yields 1 as well, so the order of the 2 elements is not properly defined. You should also handle the case of

map.get(s1).equals(map.get(s2))

when comparing two entries and return 0. Note the usage of equals and not ==, as you don't want to compare two Double objects by reference, but by value instead.

Upvotes: 2

Akash Mishra
Akash Mishra

Reputation: 712

Made few changes to your existing implementation of the comparator, in order to adhere to the contract of comparator implementation:

  • Replaced Generic parameter from String to Object(not sure if its really needed)
  • Type casting value of map.get(s1) & fetching double value to compare
  • Separated the >, < & ==

It seems to work using the below implementation of the comparator.

    HashMap<String, Double> map = new HashMap<String, Double>();

    public ValueComparator(HashMap<String, Double> map){
        this.map.putAll(map);
    }

    @Override
    public int compare(Object s1, Object s2) {
        if(((Double) map.get(s1)).doubleValue() > ((Double) map.get(s2)).doubleValue()){
            return 1;
        }
        else if (((Double) map.get(s1)).doubleValue() == ((Double) map.get(s2)).doubleValue()){
    return ((String)s1).compareTo(((String)s2));
         }
         else{
            return -1;
        }   
    }

For the below sample values:

treemap.put( "two",2.0);
   treemap.put( "one",1.0);
   treemap.put( "three",3.0);
   treemap.put( "six",6.0);
   treemap.put( "five",5.0);

Output:

First key is: one
Value against first key: 1.0

Upvotes: 1

Nguyen Pham
Nguyen Pham

Reputation: 464

Sorry not able to post comment in the question yet so have to post here as an answer. Maybe you can try first to copy the whole string to the get input to see if you still get null

Double topvalue = cosinesimilarityvalues.get(“article04_C9,article08_C12”);

I find out the problem is with your overriden compare method for custom Comparator. The below replicates your issue

    import java.util.Comparator;
import java.util.TreeMap;
public class MyTreeMapComparator {
    public static void main(String a[]){
        //the treemap sorts by key
        TreeMap<String, String> hm = new TreeMap<String, String>(new MyComp());
         //add key-value pair to TreeMap
         hm.put("java", "language");
         hm.put("computer", "machine");
         hm.put("india","country");
         hm.put("mango","fruit");
         System.out.println(hm.get("java"));
     }
}
class MyComp implements Comparator<String>{
    @Override
    public int compare(String str1, String str2) {
        if (str1.compareTo(str2) >= 0) {return 1;}
        else {return -1;}
    }
}

Then if you change to this then it works fine

    import java.util.Comparator;
import java.util.TreeMap;
public class MyTreeMapComparator {
    public static void main(String a[]){
        //the treemap sorts by key
        TreeMap<String, String> hm = new TreeMap<String, String>(new MyComp());
         //add key-value pair to TreeMap
         hm.put("java", "language");
         hm.put("computer", "machine");
         hm.put("india","country");
         hm.put("mango","fruit");
         System.out.println(hm.get("java"));
     }
}
class MyComp implements Comparator<String>{
    @Override
    public int compare(String str1, String str2) {
        if (str1.compareTo(str2) == 0) {return 0;}
        else if (str1.compareTo(str2) > 0) {return 1;}
        else {return -1;}
    }
}

Upvotes: 1

Related Questions