Treeset to order elements in descending order - java

Here is the piece of code that I have used for Java 5.0
TreeSet<Integer> treeSetObj = new TreeSet<Integer>( Collections.reverseOrder() ) ;
Collections.reverseOrder() is used to obtain a comparator in order to reverse the way the elements are stored and iterated.
Is there a more optimized way of doing it?

Why do you think this approach won't be optimized? The reverse order Comparator is simply going to be flipping the sign of the output from the actual Comparator (or output from compareTo on the Comparable objects being inserted) and I would therefore imagine it is very fast.
An alternative suggestion: Rather than change the order you store the elements in you could iterate over them in descending order using the descendingIterator() method.

TreeSet::descendingSet
In Java 6 and later, there is a method on TreeSet called descendingSet() producing a NavigableSet interface object.
public NavigableSet descendingSet()
The descending set is backed by this
set, so changes to the set are
reflected in the descending set, and
vice-versa. If either set is modified
while an iteration over either set is
in progress (except through the
iterator's own remove operation), the
results of the iteration are
undefined.
The returned set has an ordering equivalent to
Collections.reverseOrder(comparator()).
The expression
s.descendingSet().descendingSet()
returns a view of s essentially
equivalent to s.
Specified by:
descendingSet in interface NavigableSet<E>
Returns:
a reverse order view of this set
Since:
1.6

TreeSet<Integer> treeSetObj = new TreeSet<Integer>(new Comparator<Integer>()
{
public int compare(Integer i1,Integer i2)
{
return i2.compareTo(i1);
}
});
there is need to flip the result. But I guess this is just a micro-optimization... Do you really need this ?

Using descendingSet method you can reverse existing treeSet in the class
import java.util.TreeSet;
public class TreeSetDescending {
public static void main(String[] args)
{
// Declare a treeset
TreeSet<Object> ints = new TreeSet<Object>();
ints.add(2);
ints.add(20);
ints.add(10);
ints.add(5);
ints.add(7);
ints.add(3);
// Initialize treeset with predefined set in reverse order
// using descendingSet()
TreeSet<Object> intsReverse = (TreeSet<Object>)ints.descendingSet();
// Print the set
System.out.println("Without descendingSet(): " + ints);
System.out.println("With descendingSet(): " + intsReverse);
}
}

Reverse compare
You can reverse the order of the two arguments in the compare method of your Comparator.
TreeSet t = new TreeSet(new MyComparator());
{
class MyComparator implements Comparator
{
public int compare(Integer i1,Integer i2)
{
Integer I1=(Integer)i1;
Integer I2=(Integer)i2;
return I2.compareTo(I1); // return -I1compareTo(I2);
}
}
}

Related

TreeSet not arranging value in ascending order

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]
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.
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.
#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))));
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))));

Sorting ArrayList of TreeSets

I have an ArrayList of TreeSets defined like this (in Java) where n is some given number.
ArrayList<TreeSet<Integer>>(n)
Since I know that all values inside TreeSet are sorted in ascending order, that keep my List unsorted. Now I want to sort my List based on the first Element of each TreeSet in order to have both list and all treesets sorted.
Is it possible to sort just these elements which I get using list.get(i)? Will this mess up my TreeSets too?
Let's say that you already have an ArrayList<TreeSet<Integer>> initialized; we'll call it list.
You'll have to pass a custom Comparator<TreeSet<Integer>> to sort each TreeSet<Integer>:
Collections.sort(list, Comparator.comparing(TreeSet::first));
This sorts the ArrayList<TreeSet<Integer>> in ascending order according to the first element of each TreeSet<Integer>.
You can try sorting your ArrayList using a custom comparator. In this case, your custom comparator can compare the first numbers from each of two tree set elements.
Collections.sort(list, new ListOfTreeSetComparator());
class ListOfTreeSetComparator implements Comparator<TreeSet<Integer>> {
#Override
public int compare(TreeSet<Integer> ts1, TreeSet<Integer> ts2) {
return ts1.first().compareTo(ts2.first());
}
}
Note that there is a potential problem with your logic. Just because the first elements in each TreeSet have ascending order in your ArrayList does not necessarily mean that all elements would be sorted.
Here some rough idea which you can implement
Collections.sort(ArrayList, new Comparator<TreeSet<Integer>>() {
#Override
public int compare(TreeSet lhs, TreeSet rhs) {
// -1 - less than, 1 - greater than, 0 - equal
return lhs.first().compareTo(rhs.first());
}
});

Java PriorityQueue and Comparator Not Ordering correctly

I am new to Java and am trying to implement a priority queue with a custom comparator. I want to put the Sentences in the queue and have them removed in order to highest score.
For the comparator class I have:
public class SentenceScoreComparator implements Comparator<Sentence> {
#Override
public int compare(Sentence o1, Sentence o2) {
if (o2.getScore() > o1.getScore()) return -1;
//fixed typo
if (o2.getScore() < o1.getScore()) return 1;
return 0;
}
}
I then print out the sentences like so:
PriorityQueue<Sentence> allSentences = new PriorityQueue<Sentence>(new SentenceScoreComparator());
//add sentences
for(Sentence s :allSentences){
System.out.println(s.getScore());
}
but they are not in order
0.34432960587450223
0.47885099912108975
0.10991840331015199
0.36222267254836954
0.05164923572003221
0.5366117828694823
0.3891453014131773
0.0961512261934429
0.5566040852233918
0.5079687049927742
0.7628021620154812
0.6023121606121791
0.25695632228681914
0.15701049878801304
0.1260031244674359
0.36516025683986736
0.3846995962155155
I checked that the queue is using the comparator with the correct comparator method. Can someone explain what I am missing?
You have a typo in the comparator in the second if where o2 score is compared to itself.
Replace it with:
#Override
public int compare(Sentence o1, Sentence o2) {
return Double.compare(o1.getScore(), o2.getScore());
}
On top of that, as bradimus answered, PriorityQueue does not guarantee any sorted traversal. Use a regular list and sort it for that.
PriorityQueue never promised to traverse them in order. From the javadocs:
This class and its iterator implement all of the optional methods of the Collection and Iterator interfaces. The Iterator provided in method iterator() is not guaranteed to traverse the elements of the priority queue in any particular order. If you need ordered traversal, consider using Arrays.sort(pq.toArray()).

Sorting of hash set in descending

I want to sort hashset values in descending value on the basis of length of string in hash set.
HashSet<String> hs = new HashSet<String>();
hs.add("The World Tourism Organization");
hs.add("reports the following ten countries");
hs.add("as the most visited in terms of the number");
hs.add("of international travellers.");
System.out.println(hs);
My output should be
['as the most visited in terms of the number',
'reports the following ten countries',
'The World Tourism Organization',
'of international travellers.']
What is the method to sort in descending order?
A HashSet by definition doesn't sort its members. What you want is a TreeSet.
If you have a hashset you can create a treeset from it, as long as the objects are Comparable:
TreeSet ts = new TreeSet (hs);
You should use TreeSet instead of hashset or create a comparator to sort your set
You need to use a TreeSet instead of a HashSet with your own custom comparator which will sort the values based on their lengths.
Set<String> yourSet = new TreeSet<>(new Comparator<String>() {
public int compare(String o1, String o2) {
// Your comparison logic goes here
return 0;
}
});
// Add all the HashSet values to the TreeSet
yourSet.addAll(hs);
HashSet does not provide any meaningful order to the entries. The documentation says:
It makes no guarantees as to the iteration order of the set; in particular, it does not guarantee that the order will remain constant over time.
To get a sensible ordering, you need to use a different Set implementation such as TreeSet. TreeSet lets you provide a Comparator that specifies how to order the entries; something like:
public class SortByString implements Comparator<FullName>{
public int compare(FullName n1, FullName n2) {
return n1.getLastName().compareTo(n2.getLastName());
}
}

How to sort ArrayList<Long> in decreasing order?

How to sort an ArrayList<Long> in Java in decreasing order?
Here's one way for your list:
list.sort(null);
Collections.reverse(list);
Or you could implement your own Comparator to sort on and eliminate the reverse step:
list.sort((o1, o2) -> o2.compareTo(o1));
Or even more simply use Collections.reverseOrder() since you're only reversing:
list.sort(Collections.reverseOrder());
Comparator<Long> comparator = Collections.reverseOrder();
Collections.sort(arrayList, comparator);
You can use the following code which is given below;
Collections.sort(list, Collections.reverseOrder());
or if you are going to use custom comparator you can use as it is given below
Collections.sort(list, Collections.reverseOrder(new CustomComparator());
Where CustomComparator is a comparator class that compares the object which is present in the list.
Java 8
well doing this in java 8 is so much fun and easier
Collections.sort(variants,(a,b)->a.compareTo(b));
Collections.reverse(variants);
Lambda expressions rock here!!!
in case you needed a more than one line logic for comparing a and b you could write it like this
Collections.sort(variants,(a,b)->{
int result = a.compareTo(b);
return result;
});
Sort normally and use Collections.reverse();
For lamdas where your long value is somewhere in an object I recommend using:
.sorted((o1, o2) -> Long.compare(o1.getLong(), o2.getLong()))
or even better:
.sorted(Comparator.comparingLong(MyObject::getLong))
Sort, then reverse.
By using Collections.sort() with a comparator that provides the decreasing order.
See Javadoc for Collections.sort.
A more general approach to implement our own Comparator as below
Collections.sort(lst,new Comparator<Long>(){
public int compare(Long o1, Long o2) {
return o2.compareTo(o1);
}
});
The following approach will sort the list in descending order and also handles the 'null' values, just in case if you have any null values then Collections.sort() will throw NullPointerException
Collections.sort(list, new Comparator<Long>() {
public int compare(Long o1, Long o2) {
return o1==null?Integer.MAX_VALUE:o2==null?Integer.MIN_VALUE:o2.compareTo(o1);
}
});
You can also sort an ArrayList with a TreeSet instead of a comparator. Here's an example from a question I had before for an integer array. I'm using "numbers" as a placeholder name for the ArrayList.
import.java.util.*;
class MyClass{
public static void main(String[] args){
Scanner input = new Scanner(System.in);
ArrayList<Integer> numbers = new ArrayList<Integer>();
TreeSet<Integer> ts = new TreeSet<Integer>(numbers);
numbers = new ArrayList<Integer>(ts);
System.out.println("\nThe numbers in ascending order are:");
for(int i=0; i<numbers.size(); i++)
System.out.print(numbers.get(i).intValue()+" ");
System.out.println("\nThe numbers in descending order are:");
for(int i=numbers.size()-1; i>=0; i--)
System.out.print(numbers.get(i).intValue()+" ");
}
}
So, There is something I would like to bring up which I think is important and I think that you should consider. runtime and memory. Say you have a list and want to sort it, well you can, there is a built in sort or you could develop your own. Then you say, want to reverse the list. That is the answer which is listed above.
If you are creating that list though, it might be good to use a different datastructure to store it and then just dump it into an array.
Heaps do just this. You filter in data, and it will handle everything, then you can pop everything off of the object and it would be sorted.
Another option would be to understand how maps work. A lot of times, a Map or HashMap as something things are called, have an underlying concept behind it.
For example.... you feed in a bunch of key-value pairs where the key is the long, and when you add all the elements, you can do: .keys and it would return to you a sorted list automatically.
It depends on how you process the data prior as to how i think you should continue with your sorting and subsequent reverses
Comparator's comparing method can be used to compare the objects and then method reversed() can be applied to reverse the order -
list.stream().sorted(Comparator.comparing(Employee::getName).reversed()).collect(toList());
Using List.sort() and Comparator.comparingLong()
numberList.sort(Comparator.comparingLong(x -> -x));

Categories