Shruti Rawat
Shruti Rawat

Reputation: 697

sorting on the basis on a column not alphabetically

I have a bean called vulnerability. It is having a column "severity".

private String severity;

Severity can hold string value High,Medium and Low. Now whenever sorting of this bean on the basis of severity column is done it happens alphabetically i.e. High,Low and Medium. But i want the sorting to happen high,medium, low when descending and low, medium,high when ascending. I was seeing comparator to make this custom sorting but it needs to cover lots of cases. Isn't their any other way?

Upvotes: 1

Views: 1862

Answers (5)

Samer Mansour
Samer Mansour

Reputation: 1

If you want the DB to do this through JPA/Hibernate you could create a sort expression based on a simple case statement, assuming your entity is called Case:

Expression exp = criteriaBuilder.selectCase(root.get(Case_.priority)).when("High", 1).when("Medium", 2).otherwise(3);
queryBuilder.orderBy(orderDir.isAscending() ? criteriaBuilder.asc(exp) : criteriaBuilder.desc(exp));

Using case statements in an order by clause isn't great for performance, but solves it. Works with Oracle.

Upvotes: 0

manoj rana
manoj rana

Reputation: 9

Working Solution:

Collections.sort(recommendations, new Comparator() {

            private int priority(String s) {
                if (s.equalsIgnoreCase("Low")) {
                    return 1;
                } else if (s.equalsIgnoreCase("Medium")) {
                    return 2;
                } else if (s.equalsIgnoreCase("High")) {
                    return 3;
                } else {
                    return 0;
                }
            }

            @Override
            public int compare(Recommendation o1, Recommendation o2) {
                return -1 * (priority(o1.getPriority()) - priority(o2.getPriority()));
            }
        });

Upvotes: 0

Nir Alfasi
Nir Alfasi

Reputation: 53525

You can (and should) use an enum - not a String nor a int:

enum Severity {
    LOW, MEDIUM, HIGH;
}

Usage:

    List<Severity> lst = new ArrayList<Severity>();
    lst.add(Severity.MEDIUM);
    lst.add(Severity.LOW);
    lst.add(Severity.HIGH);
    for (Severity s : lst)
        System.out.println("s = " + s);

    Collections.sort(lst);

    System.out.println();

    for (Severity s : lst)
        System.out.println("s = " + s);

OUTPUT:

s = MEDIUM
s = LOW
s = HIGH

s = LOW
s = MEDIUM
s = HIGH

EDIT

Since the OP says he can't modify the usage of Strings, we can map the strings into a comparable values:

static Map<String, Integer> severities = new HashMap<String, Integer>();

static {
    severities.put("LOW",1);
    severities.put("MEDIUM",2);
    severities.put("HIGH",3);
}

public static void main(String[] args) {
    List<String> lst = new ArrayList<String>();
    lst.add("MEDIUM");
    lst.add("LOW");
    lst.add("HIGH");
    for (String s : lst)
        System.out.println("s = " + s);

    Collections.sort(lst, new Comparator<String>() {
        public int compare(String a1, String a2) {
            Integer v1 = severities.get(a1);
            Integer v2 = severities.get(a2);
            return v1.compareTo(v2);
        }
    });

    System.out.println();

    for (String s : lst)
        System.out.println("s = " + s);

}

and if you want to order the items in descending order you can sort and then reverse:

    Collections.sort(lst);
    Collections.reverse(lst);

Upvotes: 2

tucuxi
tucuxi

Reputation: 17945

There is an implicit compareTo operator defined on enums, which takes their declaration order to mean "smaller than". No additional code is needed.

enum Severity { Low, Medium, High }

Low.compareTo(High);   // returns -1
Medium.compareTo(Low); // returns 1

However, note that the names of the enum constants will be those printed by toString() (and therefore visible to users if you echo enums directly) - if you want to use different internal and external names, possibly to uphold code conventions (say, all-caps-constants), then you will need to add an enum constructor and override the enum's toString method to use the passed-in constructor attribute.


If you cannot use enums, and you cannot change your bean

Then build a Comparator for it:

public class SeverityComparator implements Comparator<String> {
     private int direction;

     public SeverityComparator(boolean reverse) {
         this.direction = reverse ? -1 : 1;
     }

     private int severity(String s) {
         if (s.equals("Low")) { // you really should have constants for the values...
             return 0;
         } else if (s.equals("Medium")) {
             return 1;
         } else if (s.equals("High")) {
             return 2;
         } else {
             throw new IllegalArgumentException("Not a severity: " + s);
         }
     }

     @Override
     public int compareTo(String other) {
         return direction * (severity(this) - severity(other));
     }
}

Use as

Collections.sort(listOfSeverities, new SeverityComparator(false)); // ascending
Collections.sort(listOfSeverities, new SeverityComparator(true)); // descending  

Upvotes: 1

rgrebski
rgrebski

Reputation: 2584

@alfasin answer is correct but i would suggest using guava's Ordering:

    import com.google.common.base.Function;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Ordering;

import javax.annotation.Nullable;
import java.util.List;

public class SeveritySortTest {

    private static final List<Severity> SEVERITY_LIST = ImmutableList.copyOf(Severity.values());

    public static void main(String[] args) {

        Ordering<Severity> severityOrdering = Ordering.natural().onResultOf(new Function<Severity, Integer>() {
            @Nullable
            @Override
            public Integer apply(@Nullable Severity input) {
                return input.getSeverity();
            }
        });

        List<Severity> sortedAscending = severityOrdering.sortedCopy(SEVERITY_LIST);
        List<Severity> sortedDescending = severityOrdering.reverse().sortedCopy(SEVERITY_LIST);

    }


    enum Severity {
        LOW(1), MEDIUM(2), HIGH(3);

        private int severity;

        Severity(int s) {
            severity = s;
        }

        int getSeverity() {
            return severity;
        }
    }
}

Upvotes: 0

Related Questions