0

I'm trying to build a select menu object. I'm using hibernate criteria to build my object list. I'm trying to take my joined table object and add it to a set to eliminate duplicates. I then want to order the set by a property within the object, once ordered I need to add it to an arraylist and finally add one additional entry to the end of the list.

Here's what I have thus far.

public class Computer {

    private String name;

    //other properties getter/setter
}

Select menu query

public List<Computer> getComputerList() {
    //Hibernate critera query
    List<ComputerConfiguration> results = session.criteraQuery(ComputerConfiguration.class).add(Restrictions.eq("processor", "amd")).list();

    Set<Computer> computerSet = HashSet();

    //Get joined object and add to set to remove duplicates
    for(ComputerConfiguration computerConfiguration : results) {
        computerSet.add(computerConfiguration.getComputer());
    }

    List<Computer> computers = new ArrayList<>(computerSet);
    //Need to somehow order by computer.getName();

    //Lastly add the following
    computers.add("Other");

    //Return computers to select model
    return computers;
}

What is the most efficient way to remove duplicate objects and then order them by the property name? I tried just initially ordering the critera query, however the set didn't appear to hold its position.

Thanks.

BrianC
  • 1,793
  • 1
  • 18
  • 26
Code Junkie
  • 7,602
  • 26
  • 79
  • 141
  • you can change your query to return only unique results and you don't need to use Set at all – Jakub H Mar 03 '14 at 15:18
  • @Jakub hr Unfortunately I don't know how to accomplish that. – Code Junkie Mar 03 '14 at 15:23
  • You should describe your `Computer` class in more detail. Does it have an appropriate implementation of `equals` (and `hashCode`)? What is the sorting cirterion that should be used? – Marco13 Mar 03 '14 at 15:25
  • I currently only override id "pk" with hash equals. Other than my id, there is just name in the class. Very simple lookup table. – Code Junkie Mar 03 '14 at 15:27

3 Answers3

2

Use a TreeSet which will sort the elements inside it. You can provide a custom Comparator when creating the set:

Set<Computer> computerSet = new TreeSet<Computer>(new Comparator<Computer>() {
    @Override
    public int compare(Computer computer1, Computer computer2) {
        //write the logic to define which computer is greater than the other...
    }
});

Note that your Computer class won't need to implement equals nor hashCode to be used inside a TreeSet.

Luiggi Mendoza
  • 85,076
  • 16
  • 154
  • 332
  • Your should be **very** careful here. Using a comparator that is inconsistent with `equals` might lead to problems. Explicitly mentioned in the JavaDoc of TreeSet: *Note that the ordering maintained by a set (whether or not an explicit comparator is provided) must be consistent with equals if it is to correctly implement the Set interface* – Marco13 Mar 03 '14 at 15:23
1

Using a HashSet to make sure that the computers are unique (just like you're currently doing it) is fine - assuming that you have implemented hashCode and equals appropriately.

In order to sort the List of computers by name, you can just write

Collections.sort(computers, new Comparator<Computer>()
{
    @Override
    public int compare(Computer c0, Computer c1)
    {
        return c0.getName().compareTo(c1.getName());
    }
});

While it might be tempting to solve this with a TreeSet (because it can sort and remove duplicates in one run), you should carefully think about whether your comparison criterion is consistent with equals as described in the JavaDoc of TreeSet and Comparator:

The ordering imposed by a comparator c on a set of elements S is said to be consistent with equals if and only if c.compare(e1, e2)==0 has the same boolean value as e1.equals(e2) for every e1 and e2 in S.

( http://docs.oracle.com/javase/7/docs/api/java/util/Comparator.html )

The crucial question here is: Can there be two computers that have the same name (as returned by getName()) but should still not be considered as "equal"?

However, if the sorting criterion is consistent with equals, then using TreeSet with the appropriate comparator is feasible.

Marco13
  • 53,703
  • 9
  • 80
  • 159
  • To answer your question, no there is no chance two computers could have the same name, example Dell, HP, IBM etc. Why not use the SortedSet like user3173787 suggest? – Code Junkie Mar 03 '14 at 16:12
  • @CodeJunkie The `SortedSet` approach is basically the same as the `TreeSet` approach that was already suggested by Luiggi Mendoza. And again: When the sorting is consistent with equals, this is a feasible (and somewhat easier) approach. The only difference in the answers is that user3173787 suggested to let `Computer` implement `Comparable`, which I would **not** recommend: There is no "natural ordering" between computers. Also see http://stackoverflow.com/a/21659849 – Marco13 Mar 03 '14 at 16:26
  • I ended up using the Treeset as Luiggi Mendoza suggested, but decided to mark you as the best answer do to the fact it's explained well and most likely will help others. . – Code Junkie Mar 03 '14 at 17:34
1

You can try to use a SortedSet to actually sort the computer while populating the set : SortedSet

Also, I don't quite understand your line

computers.add("Other")

computers is a Computer object ArrayList you it may not work. So here's my complete solution :

First, make the Computer Object comparable :

public class Computer implements Comparable<Computer> {

    private String name;

    public Computer (String name) { this.name = name; }

    public int compareTo(Computer c) {          
       return name.compareTo(c.name) ;          
   }
}

You can now use a SortedSet like this :

public List<Computer> getComputerList() {
    List<ComputerConfiguration> results = session.criteraQuery(ComputerConfiguration.class).add(Restrictions.eq("processor", "amd")).list();

    SortedSet<Computer> computerSet = new TreeSet<>();
    for(ComputerConfiguration computerConfiguration : results) {
        computerSet.add(computerConfiguration.getComputer());
    }
    computerSet.add(new Computer("Other");

    List<Computer> computers = new ArrayList<>(computerSet);
    return computers;
}
  • Opps, simple mistake while writing my question from memory, it is suppose to be a new Computer("Other"); and it's purpose is to add an "Other" option to my select menu. I'll read up on the SortedSet. I'm wondering if I order my results in the hibernate query if SortedSet would maintain the insert order. If so, there would be no need for the comparator. – Code Junkie Mar 03 '14 at 16:01
  • if your results are already sorted , no need for a SortedSet and the comparator. You can simply use a simple Set, iterate through the results and add them. – user3173787 Mar 03 '14 at 16:16
  • Interesting, I was under the impression the set wouldn't hold the insert order. Okay I'll try things out in a poj. Thanks – Code Junkie Mar 03 '14 at 16:32