Link to home
Start Free TrialLog in
Avatar of Johannne1
Johannne1Flag for Canada

asked on

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.
Avatar of Johannne1
Johannne1
Flag of Canada image

ASKER

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.

Sorry the zone of this question is written Perl but it should be Java. I am looking for a java data structure and method.
Avatar of CEHJ
>>
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

You should define Comparator which implements compare() method based on the second field
and then use m,ethod Collections.sort(Collection, Comparator)
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

>>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
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

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

I guess, CEHJ just forgot to add: you'd probably be better off just sorting a List<Rule> as for_yan suggested  :)
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.
>>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
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


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

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.




SOLUTION
Avatar of for_yan
for_yan
Flag of United States of America image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
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?
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
>>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
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

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

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!

Sure, I meant this Rule as an example to be replaced by your Rule
Great, it works!
>>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)
ASKER CERTIFIED SOLUTION
Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
And thios is the output of the code in the  above post ID:36912915Author
e  aa
a  b
a  c

Open in new window

Johannne1, can you tell me why you ignored my comments please?