41

I am trying to sort elements of a set but unable to do so far. here is my code which i am trying to do

public static void main(String [] args){
    Set<String> set=new HashSet<String>();
    set.add("12");
    set.add("15");
    set.add("5");
    List<String> list=asSortedList(set);
}

public static
<T extends Comparable<? super T>> List<T> asSortedList(Collection<T> c) {
  List<T> list = new ArrayList<T>(c);
  Collections.sort(list);
  return list;
}

but this or other way is not working since its all time giving me the same order in which they have been filled 12,15,5

Yan Khonski
  • 12,225
  • 15
  • 76
  • 114
Umesh Awasthi
  • 23,407
  • 37
  • 132
  • 204

6 Answers6

69

Use a SortedSet (TreeSet is the default one):

SortedSet<String> set=new TreeSet<String>();
set.add("12");
set.add("15");
set.add("5");
List<String> list=new ArrayList<String>(set);

No extra sorting code needed.

Oh, I see you want a different sort order. Supply a Comparator to the TreeSet:

new TreeSet<String>(Comparator.comparing(Integer::valueOf));

Now your TreeSet will sort Strings in numeric order (which implies that it will throw exceptions if you supply non-numeric strings)

Reference:

Sean Patrick Floyd
  • 292,901
  • 67
  • 465
  • 588
31

If you sort the strings "12", "15" and "5" then "5" comes last because "5" > "1". i.e. the natural ordering of Strings doesn't work the way you expect.

If you want to store strings in your list but sort them numerically then you will need to use a comparator that handles this. e.g.

Collections.sort(list, new Comparator<String>() {
    public int compare(String o1, String o2) {
        Integer i1 = Integer.parseInt(o1);
        Integer i2 = Integer.parseInt(o2);
        return (i1 > i2 ? -1 : (i1 == i2 ? 0 : 1));
    }
});

Also, I think you are getting slightly mixed up between Collection types. A HashSet and a HashMap are different things.

mikej
  • 65,295
  • 17
  • 152
  • 131
  • 1
    +1 ... although: Subtracting one int from another during comparison could lead to underflow; an explicit comparison would be safer. – Adamski Nov 12 '10 at 15:31
  • `o1 == o2` may lead to unexpected results with non-interned Strings. Use `o1.equals(o2)` (you could also do `o1.intern()==o2.intern()` but that's awful) – Sean Patrick Floyd Nov 12 '10 at 15:51
  • Thanks @seanizer - I didn't actually mean to be comparing the Strings. I lost the calls to `parseInt` in the edit. I've revised it again. – mikej Nov 12 '10 at 15:57
  • 1
    Couldn't your return statement be reduced to `return i1.compareTo(i2);`? – Adam Paynter Nov 26 '10 at 18:07
7

You're using the default comparator to sort a Set<String>. In this case, that means lexicographic order. Lexicographically, "12" comes before "15", comes before "5".

Either use a Set<Integer>:

Set<Integer> set=new HashSet<Integer>();
set.add(12);
set.add(15);
set.add(5);

Or use a different comparator:

Collections.sort(list, new Comparator<String>() {
    public int compare(String a, String b) {
        return Integer.parseInt(a) - Integer.parseInt(b);
    }
});
Matt Ball
  • 354,903
  • 100
  • 647
  • 710
4

Use the Integer wrapper class instead of String because it is doing the hard work for you by implementing Comparable<Integer>. Then java.util.Collections.sort(list); would do the trick.

dimitrisli
  • 20,895
  • 12
  • 59
  • 63
1

Strings are sorted lexicographically. The behavior you're seeing is correct.

Define your own comparator to sort the strings however you prefer.

It would also work the way you're expecting (5 as the first element) if you changed your collections to Integer instead of using String.

Jonathon Faust
  • 12,396
  • 4
  • 50
  • 63
0

You need to pass in a Comparator instance to the sort method otherwise the elements will be sorted in their natural order.

For more information check Collections.sort(List, Comparator)

Sean Patrick Floyd
  • 292,901
  • 67
  • 465
  • 588
Faisal Feroz
  • 12,458
  • 4
  • 40
  • 51