Reputation: 510
I am trying to create a TreeSet to sort the strings which are inserted to be in an ascending order. I am using below code for entering values in TreeSet.
TreeSet<String> ts = new TreeSet<String>();
ts.add("@Test0");
ts.add("@Test1");
ts.add("@Test2");
ts.add("@Test3");
ts.add("@Test10");
ts.add("@Test4");
System.out.println("Tree set :: "+ts);
Output:
Tree set :: [@Test0, @Test1, @Test10, @Test2, @Test3, @Test4]
Upvotes: 2
Views: 1340
Reputation: 102892
You've used the no-args TreeSet constructor. This means TreeSet will order its elements based on natural order. It's the way the objects compare themselves: It means the things you add must be of a type that implements Comparable<Self>
. String does that: The String class is defined to implement Comparable<String>
. However, the way strings compare themselves is lexicographically. 10 comes before 2 for the same reason that aa comes before b.
You have two routes available to fix this:
Don't put strings in there but some other object that implements Comparable and does it right. Perhaps a class Thingie {String name; int idx;}
.
Pass a Comparator
as first and only argument to your TreeSet class. Write code that determines that @Test10
comes before @Test2
. Then, TreeSet uses this comparator to determine ordering and won't use the one built into strings.
Upvotes: 4
Reputation: 311188
As @Jems noted in the comment, strings are sorted lexichographically, so "@Test10" will come before "@Test2". If could however, supply a custom Comparator
to define the order you need. E.g., if you know all the strings will have the form of "@Test" followed by a number, you could extract this number and sort accordingly:
TreeSet<String> ts =
new TreeSet<>(Comparator.comparingInt(s -> Integer.parseInt(s.substring(5))));
Upvotes: 1
Reputation: 40034
Specify the Comparator to sort on the number part only. This removes all but the number portion, converts that to an integer and sorts on that.
TreeSet<String> ts = new TreeSet<String>(Comparator.comparing(
s -> Integer.valueOf(s.replace("@Test", ""))));
ts.add("@Test0");
ts.add("@Test1");
ts.add("@Test2");
ts.add("@Test3");
ts.add("@Test10");
ts.add("@Test4");
System.out.println(ts);
prints
[@Test0, @Test1, @Test2, @Test3, @Test4, @Test10]
This works for the shown example. You may need to modify it somewhat for more varied data. But it demonstrates the idea.
Upvotes: 1
Reputation: 72844
@Test10
comes before @Test2
because 1
comes before 2
. That's how the default ordering of String
works (String
implements the interface Comparable
to do this sorting).
To solve your issue you need to provide a custom Comparator
to the TreeSet
, and do the comparison by parsing the integer within the string:
TreeSet<String> ts = new TreeSet<String>(new Comparator<String>() {
@Override
public int compare(String s1, String s2) {
return Integer.parseInt(s1.substring(5)) - Integer.parseInt(s2.substring(5));
}
});
The comparator can be constructed using the static convenience method:
TreeSet<String> ts = new TreeSet<>(Comparator.comparing(s -> Integer.parseInt(s.substring(5))));
Upvotes: 1