Reputation: 69
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
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
Reputation: 712
Made few changes to your existing implementation of the comparator, in order to adhere to the contract of comparator implementation:
map.get(s1)
& fetching double value to compareIt 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
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