Sorting (HashSet)

sorting on second member of an object.
I have: an existing structure:

private Set<Rule> dAllRules = new HashSet<Rule>();

where the object Rule defined with five members
Id1 (String)
Id2 (String)
Id3 (String)
Id4 (String)
Id5 (String)

I have the existing code:

dAllRules.add(newObject);

example of data:


(first object)
Id1 = "ABC"
Id2 = "1"
Id3 = "hello1"
Id4 = "123"
Id5 = "5"

(second object)
Id1 = "DEF"
Id2 = "3"
Id3 = "hello2"
Id4 = "124"
Id5 = "1"

if i print or access objects in dAllRules
might print object #1 or object #2 since HashSet is not sorted.


I need to have the above data sorted on the second member of the object.
so that output/access would always be object #1 or object #2.

In other words I want to have a structure that contains objects of type Rule
that are sorted by the object's second memeber (Id2).
What is the easiest way to do this? I can add a new structure if I want.
Johannne1Asked:
Who is Participating?
 
for_yanCommented:
CEHJ is right - this is absolutely clean example
how it works when MyComp is a separate class, all compiliing and executing
correctly.

Strange as it may seem, it is still a little bit tricky to do,
 just wanted to have it sitting here:


package comparatortest;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;


public class CompTest {

    public static void main(String[] args) {
        ArrayList<Rule> ar = new ArrayList<Rule>();
        ar.add(new Rule("a","b"));
        ar.add(new Rule("a","c"));
        ar.add(new Rule("e","aa"));

        Collections.sort(ar, new MyComp());

        for(Rule r: ar){
            System.out.println(r);
        }

   }


}


 class Rule  {
    String s1;
    String s2;

    public Rule(String s1, String s2){

        this.s1 = s1;
        this.s2 = s2;

    }


   public String getId1() {return s1;}
  public  String getId2() {return s2;}

    public String toString(){
        return s1 + "  " + s2;
    }



}

class MyComp implements Comparator<Rule> {

       public int compare(Rule r1, Rule r2){

           return r1.getId2().compareTo(r2.getId2());

       }

}

Open in new window

0
 
Johannne1Author Commented:
I should precise that the sorting is desired on Id2 of the object. So if you have many
objects,
object 1 has Id2=4, object 2 Id2=3, object3 Id2=1, Object4 Id=6

the sorting occurs on Id2, so correct order is:

Object 3, Object2, Object1, and Object 4.
0
 
Johannne1Author Commented:

Sorry the zone of this question is written Perl but it should be Java. I am looking for a java data structure and method.
0
Cloud Class® Course: Microsoft Azure 2017

Azure has a changed a lot since it was originally introduce by adding new services and features. Do you know everything you need to about Azure? This course will teach you about the Azure App Service, monitoring and application insights, DevOps, and Team Services.

 
CEHJCommented:
>>
In other words I want to have a structure that contains objects of type Rule
that are sorted by the object's second memeber (Id2).
>>

You need something like
Set<Rule> rules = new TreeSet<Rule>(new Comparator<Rule>() {
	public int compare(Rule r1, Rule r2) {
		return r1.getId2().compareTo(r2.getId2());
	}
}

Open in new window

0
 
for_yanCommented:
You should define Comparator which implements compare() method based on the second field
and then use m,ethod Collections.sort(Collection, Comparator)
0
 
for_yanCommented:
HashSet deso not have idea of the order - so you need to put to list before resorting

This is the  way without generics:

I'll do with generics later.

        HashSet hs = new HashSet();

        hs.add(new Rule("a","b"));

           hs.add(new Rule("c","d"));

          hs.add(new Rule("c","aa"));

        ArrayList list1 = new ArrayList();
        list1.addAll(hs);

        Collections.sort(list1, new MyComp());

        for (Object r : list1){

            System.out.println((Rule) r);

        }



public class Rule {
    String s1;
    String s2;

    public Rule(String s1, String s2){

        this.s1 = s1;
        this.s2 = s2;

    }


   public String getString1() {return s1;}
  public  String getString2() {return s2;}

    public String toString(){
        return s1 + "  " + s2;
    }

}
import java.util.Comparator;

public class MyComp implements Comparator{

    public int compare(Object r1, Object r2){


        
        return  (((Rule)r1).getString2()).compareTo(((Rule)r2).getString2());
    }

}

Open in new window


Output:
c  aa
a  b
c  d

Open in new window

0
 
CEHJCommented:
>>so you need to put to list

You don't need to create yet another collection - just use a TreeSet in the first place, as i mentioned
0
 
for_yanCommented:
This is with generics


        HashSet <Rule>hs = new HashSet<Rule>();

        hs.add(new Rule("a","b"));

           hs.add(new Rule("c","d"));

          hs.add(new Rule("c","aa"));

        ArrayList<Rule> list1 = new ArrayList<Rule>();
        list1.addAll(hs);

        Collections.sort(list1, new MyComp<Rule>());

        for (Rule r : list1){

            System.out.println( r);

        }

class Rule {
    String s1;
    String s2;

    public Rule(String s1, String s2){

        this.s1 = s1;
        this.s2 = s2;

    }


   public String getId1() {return s1;}
  public  String getId2() {return s2;}

    public String toString(){
        return s1 + "  " + s2;
    }

}


class MyComp<T> implements Comparator<T>{

    public int compare(T r1, T r2){

             return((Rule)r1).getId2().compareTo(((Rule)r2).getId2());
        

    }

}

Open in new window


Ouptput:
c  aa
a  b
c  d

Open in new window

0
 
CEHJCommented:
Sorry, there was a typo in my code - should have been as below.

Another thing: if id2 is not unique, you can't use the TreeSet and you'd probably be better off just sorting a List<Rule>
Set<Rule> rules = new TreeSet<Rule>(new Comparator<Rule>() {
	    public int compare(Rule r1, Rule r2) {
		return r1.getId2().compareTo(r2.getId2());
	    }
	});

Open in new window

0
 
for_yanCommented:
I guess, CEHJ just forgot to add: you'd probably be better off just sorting a List<Rule> as for_yan suggested  :)
0
 
Johannne1Author Commented:
Hi CEHJ,
Yeah you are right, id2 is not unique, actuall in an object, what is unique is
id1+id2, so you could have an object 1 with 'first'+'one" and object 2 with 'second'+'one',
I am looking throught all the suggestions.
0
 
CEHJCommented:
>>I guess, CEHJ just forgot to add: you'd probably be better off just sorting a List<Rule> as for_yan suggested  :)

Well it seemed to me you were suggesting to move between a Set and a List. I'm saying - forget the Set
0
 
for_yanCommented:
If you originallly already have stuff in HashSet move it to list, if you are just
collecting them - certainly forget the set and start with the List - especially if you have
objects with the same id2
0
 
for_yanCommented:


If you are in the position to modify the class Rule just implement Comparable
and it will be the simplest like below:
      ArrayList<Rule> list1 = new ArrayList<Rule>();

        list1.add(new Rule("a","b"));

           list1.add(new Rule("c","d"));

          list1.add(new Rule("c","aa"));



                   Collections.sort(list1);


   

        for (Rule r : list1){

            System.out.println( r);

        }

class Rule implements Comparable<Rule> {
    String s1;
    String s2;

    public Rule(String s1, String s2){

        this.s1 = s1;
        this.s2 = s2;

    }


   public String getId1() {return s1;}
  public  String getId2() {return s2;}

    public String toString(){
        return s1 + "  " + s2;
    }

     public int compareTo( Rule r){

             return s2.compareTo(r.getId2());


    }

}

Open in new window

Ouput
c  aa
a  b
c  d

Open in new window

0
 
Johannne1Author Commented:
Hi Yan,
Your list suggestion (as well as CEHJ also suggested) would work. The only probably is I can't get comparator to work.

I am able to do: add the hashset to the array list.

        ArrayList list1 = new ArrayList();
        list1.addAll(hs);

but the myComp() is causing problems.
        Collections.sort(list1, new MyComp());

I can't seem to be able to get the comparator to work.




0
 
for_yanCommented:
I compiled and executed both
all three codes but try this one:

        HashSet <Rule>hs = new HashSet<Rule>();

        hs.add(new Rule("a","b"));

           hs.add(new Rule("c","d"));

          hs.add(new Rule("c","aa"));

        ArrayList<Rule> list1 = new ArrayList<Rule>();
        list1.addAll(hs);

        Collections.sort(list1, new MyComp<Rule>());

        for (Rule r : list1){

            System.out.println( r);

        }

class Rule {
    String s1;
    String s2;

    public Rule(String s1, String s2){

        this.s1 = s1;
        this.s2 = s2;

    }


   public String getId1() {return s1;}
  public  String getId2() {return s2;}

    public String toString(){
        return s1 + "  " + s2;
    }

}


class MyComp<T> implements Comparator<T>{

    public int compare(T r1, T r2){

             return((Rule)r1).getId2().compareTo(((Rule)r2).getId2());
        

    }

}

Open in new window

0
 
Johannne1Author Commented:
Yan, I am on the case, I am trying these..

I was able to add to the class Rule but for the class myComp to I put this in a separate file?
0
 
for_yanCommented:
It does not matter - if you declaer it public you should put it in separate file MyComp.java
or you can purt in the same file - just
class MyComp
wuithout paublic
0
 
CEHJCommented:
>>The only probably is I can't get comparator to work.

The Comparator i posted above works fine - i tested it. You can use the same one for any kind of Collection
0
 
CEHJCommented:
If you want it as a standalone class (easier to work with) then it's
private class MyComp implements Comparator<Rule> {
	public int compare(Rule r1, Rule r2) {
	    return r1.getId2().compareTo(r2.getId2());
	}
    }

Open in new window

0
 
for_yanCommented:
CEHJ is right you can use the same anonymous comparator fas he sugggested for  List

       ArrayList<Rule> list1 = new ArrayList<Rule>();

        list1.add(new Rule("a","b"));

           list1.add(new Rule("c","d"));

          list1.add(new Rule("c","aa"));



                   Collections.sort(list1, new Comparator<Rule>() {
	    public int compare(Rule r1, Rule r2) {
		return r1.getId2().compareTo(r2.getId2());
	    }
	});




        for (Rule r : list1){

            System.out.println( r);

        }

Open in new window


Output:

c  aa
a  b
c  d

Open in new window

0
 
Johannne1Author Commented:
Hi Yan,
I found my problem..

      .... MyComp.compare(MyComp.java:18)
      at java.util.Arrays.mergeSort(Arrays.java:1270)
      at java.util.Arrays.mergeSort(Arrays.java:1281)
      at java.util.Arrays.mergeSort(Arrays.java:1281)
      at java.util.Arrays.mergeSort(Arrays.java:1281)
      at java.util.Arrays.sort(Arrays.java:1210)
      at java.util.Collections.sort(Collections.java:159)

the line of code that it doesn't like is;

    return((PSXPmRule)r1).getId2().compareTo(((PSXPmRule)r2).getId2());

but really what it was I already had class Rule and I was re-declarng s1 and s2 instead of
using my existing item1 and item2 of my object.

It is working very well, by implementing comparable in existing Rule class or declaring separate
file or inner class.
thanks a lot!

0
 
for_yanCommented:
Sure, I meant this Rule as an example to be replaced by your Rule
Great, it works!
0
 
CEHJCommented:
>>return((PSXPmRule)r1).getId2().compareTo(((PSXPmRule)r2).getId2());

You can get rid of all that casting by genericizing the Comparator as in my  example (change the type accordingly)
0
 
for_yanCommented:
And thios is the output of the code in the  above post ID:36912915Author
e  aa
a  b
a  c

Open in new window

0
 
CEHJCommented:
Johannne1, can you tell me why you ignored my comments please?
0
Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.

All Courses

From novice to tech pro — start learning today.