1

I have read a lot about this in this forum and other fora, but i still cannot get a concrete answer. Anyway i decided to do it like this:

Here is a class to hold a string and an integer:

public class Tuple{

    private String token;
    private int docID;



    public Tuple(String token, int docID) {
        this.token = token;
        this.docID = docID;
    }

    public String getToken() {
        return token;
    }
    public void setToken(String token) {
        this.token = token;
    }
    public int getDocID() {
        return docID;
    }
    public void setDocID(int docID) {
        this.docID = docID;
    }

}

And then, i create an array-list to put these tuples private ArrayList<Tuple> temps = new ArrayList<>();

Then i populate the arraylist like this:

for ( int i = 0; i < numberOfDocs; i++ )
{
    Tuple cat = new Tuple(Double.toString(vect[i]),i);
    temps.add(cat);
}

Eventually, I am sorting the array like this:

public void sortTmp() 
{
    Collections.sort(temps, new Comparator<Tuple>() 
    {
        @Override
        public int compare(Tuple tr2, Tuple tr1)
        {
            return tr2.getToken().compareTo(tr1.getToken());
        }
    });
}

There is some problem with java and doubles and i cannot use directly my double matrix so i have to do Double.toString() . The results are sorted, but not entirely correct because string calculation from double is not very accurate in terms of double number sorting.

Any ideas?

6
  • 1
    Sorting Lexically is probably not what you want. Why can't you use Doubles? Or better: what makes you think you can't? "There is some problem with java and doubles" - mostly it's the developers who have problems with doubles rather than java. Commented Feb 15, 2017 at 11:27
  • @Fildor this particular line return tr2.getToken().compareTo(tr1.getToken()); is wrong when i change everything from string type to double type. According to my IDE: double cannot be dereferenced Commented Feb 15, 2017 at 11:31
  • 1
    Yes, then change that line so it works for double. You can use the Double wrapper if you need to use compareTo. Commented Feb 15, 2017 at 11:33
  • 1
    Yuo should read this explaining that call a method on a primitive give that problem. Using a wrapper should solve it Commented Feb 15, 2017 at 11:34
  • 1
    For example do return Double.compare( tr2.getToken(), tr1.getToken() ); (when changing so that getToken() returns double) Commented Feb 15, 2017 at 11:35

5 Answers 5

4

If you are comparing doubles lexicographically, by their String representation, you might indeed find some unexpected results.

You could either:

  • refactor Tuple so that token is a double (or wrapper Double if you want to invoke compareTo on the instance)
  • otherwise, in your Comparator, you can invoke Double.parseDouble on your Strings (which should be relatively safe since the Strings come from doubles in the first place), and invoke compareTo on the returned Double wrapper.

The last option sounds quite ugly because you have a bunch of seemingly unnecessary back-and-forth conversions between Double and String and vice-versa.

It would also imply a performance degradation, since compareTo will be invoked multiple times when sorting your collection.

Sign up to request clarification or add additional context in comments.

4 Comments

Thanks for your input. What do you mean by wrapper Double? I tried to change my Tuple class; where string, i put double, but in line return tr2.getToken().compareTo(tr1.getToken()); i am getting double cannot be dereferenced error.
@Javac Double != double the latter is primitive. You cannot call functions on it like you are trying to. Double is a wrapper for that primitive type to allow exactly this (amongst other purposes). Going form double to its corresponding Double is referred to as "boxing".
@Javac if you want to use primitives, you can invoke static Double.compare(double d1, double d2) instead of invoking compareTo. Otherwise you can refactor with Double wrappers as I was saying and Fildor pointed out too.
I am accepting this one. It was the Double. Thanks
3

You can store token as double in your Tuple and implements Comparable interface. in getToken you can return string presentation of double in form which you are actually needed.

public class Tuple implements Comparable<Tuple>{

    private double token;
    private int docID;

    public Tuple(double token, int docID) {
        this.token = token;
        this.docID = docID;

    }

    public String getToken() {
        return String.valueOf(token);
    }
    public void setToken(double token) {
        this.token = token;
    }
    public int getDocID() {
        return docID;
    }
    public void setDocID(int docID) {
        this.docID = docID;
    }

    @Override
    public int compareTo(Tuple o) {
        return Double.compare(this.token, o.token);
    }
}

Comments

0

If you really need to convert doubles into strings, it's safer to use

BigDecimal.valueOf(vect[i])).toString(); 

since it handles double unpredictability.

1 Comment

Well, he shouldn't do that at all. Sorting Lexicographically on doubles will surely introduce surprises. Just think of values that will be represented in Mathematical notation ...
0

I got the same idea as Vlad Bochenin:

You just implement Comparable and override compareTo:

public class Tuple implements Comparable<Tuple> {

    public Double token;
    public int docID;

    public Tuple(final double token, final int docID) {
        this.token = token;
        this.docID = docID;
    }

    @Override
    public int compareTo(final Tuple o) {
        return this.token.compareTo(o.token);
    }
}

And a unit test:

public class TestTuple {

    @Test
    public void testSort() {
        final Random r = new Random(System.currentTimeMillis());
        final int numberOfDocs = 100;
        final ArrayList<Tuple> temp = new ArrayList<Tuple>();
        for (int i = 0; i < numberOfDocs; i++) {
            temp.add(new Tuple(r.nextDouble(), i));
        }
        Collections.sort(temp);

        Tuple old = temp.get(0);
        // test if sorted
        for (final Tuple next : temp) {
            Assert.assertTrue(next.token >= old.token);
            old = next;
        }
    }
}

Comments

-1

You can store token as double in your Tuple and implements Comparable interface. in getToken you can return string presentation of double in form which you are actually needed.

private double token;
private int docID;

public Tuple(double token, int docID) {
    this.token = token;
    this.docID = docID;

}

public String getToken() {
    return String.valueOf(token);
}
public void setToken(double token) {
    this.token = token;
}
public int getDocID() {
    return docID;
}
public void setDocID(int docID) {
    this.docID = docID;
}

@Override
public int compareTo(Tuple o) {
    return Double.compare(this.token, o.token);
}

}

To see More about CompareTo

2 Comments

this is all copy of my answer (and my poor English ), without any reference on it. Is it kind of joke?
If you want to add the link to Vlad's answer, use a comment. Don't copy his answer.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.