HiveBrain v1.2.0
Get Started
← Back to all entries
snippetjavaMinor

Sort ArrayList in a better way

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
sortarraylistwaybetter

Problem

I have a list of categories (in this example I used String but in my project I have a model) which must be sorted like this:

  • on top we should have 2 categories which have a fixed position in the list (in this example (C, F))



  • at the bottom of the list we should have 3 categories which have a fixed position in the list (in this example (R, M, P))



  • in the middle of the list we should have the rest of the elements sorted alphabetically



I want to know if there is a better solution than I used, for sorting the list this way. I do not want to use HashMap, so if anyone could find a better solution for sorting the ArrayList, I would highly appreciate it.

List categories = new ArrayList<>();
    categories.add("A");
    categories.add("B");
    categories.add("C");
    categories.add("D");
    categories.add("E");
    categories.add("F");
    categories.add("G");
    categories.add("H");
    categories.add("I");
    categories.add("J");
    categories.add("K");
    categories.add("L");
    categories.add("M");
    categories.add("N");
    categories.add("O");
    categories.add("P");
    categories.add("Q");
    categories.add("R");

    sortCategories(categories);


The sortCategories() method is:

```
public void sortCategories(List categories) {
List topCategories = new ArrayList<>();
List bottomCategories = new ArrayList<>();

for (String category : categories) {
if (category.equals("C")) {
topCategories.add(category);
break;
}
}

for (String category : categories) {
if (category.equals("F")) {
topCategories.add(category);
break;
}
}

for (String category : categories) {
if (category.equals("R")) {
bottomCategories.add(category);
break;
}
}

for (String category : categories) {
if (category.equals("M")) {
bottomCategories.add(category);
break;
}
}

Solution

You should not hard-code category values into the code, but rather make them configurable, so that your code may be re-used with other top/bottom category values. Since you have a specific sorting algorithm, it is probably best to create a custom comparator, which encapsulates all of the sorting logic. That comparator would be initialized with the values allowed for top/bottom categories, and would do the sorting, taking these values into account.

Using the comparator should be as simple as:

List allCategories = Arrays.asList(
            "A", "B", "C", "D", "E", "F",
            "G", "H", "I", "J", "K", "L",
            "M", "N", "O", "P", "Q", "R"
            );
    List topCategories = Arrays.asList("C", "F");
    List bottomCategories = Arrays.asList("M", "P", "R");
    Collections.sort(allCategories, new CategoryComparator(topCategories, bottomCategories));


There are many ways to implement such a comparator.The main idea is to extend the comparison logic: in addition to comparing values, you also compare their belonging to a particular category, and adjust the score consequently. As a result, values belonging to the top category should be put on top, and if two values belong to the same category, they should be compared according to their natural order.

public class CategoryComparator implements Comparator {

    private static final int POSITIVE_SCORE = +1;
    private static final int NEGATIVE_SCORE = -1;
    private static final int TOP_SCORE_ADJUSTMENT = -2;
    private static final int BOTTOM_SCORE_ADJUSTMENT = +2;

    private Set topCategories;
    private Set bottomCategories;

    public CategoryComparator(Collection topCategories, Collection bottomCategories) {
        this.topCategories = new HashSet<>(topCategories);
        this.bottomCategories = new HashSet<>(bottomCategories);
    }

    @Override
    public int compare(String o1, String o2) {
        return normalizeScore(o1.compareTo(o2)) + ajustScoreForCategory(o1) - ajustScoreForCategory(o2);
    }

    private int normalizeScore(int score) {
        if (score  0) {
            return POSITIVE_SCORE;
        }
        return 0;
    }

    private int ajustScoreForCategory(String value) {
        int scoreAdjustment = 0;
        if (topCategories.contains(value)) {
            scoreAdjustment += TOP_SCORE_ADJUSTMENT;
        }
        if (bottomCategories.contains(value)) {
            scoreAdjustment += BOTTOM_SCORE_ADJUSTMENT;
        }
        return scoreAdjustment;
    }
}

Code Snippets

List<String> allCategories = Arrays.asList(
            "A", "B", "C", "D", "E", "F",
            "G", "H", "I", "J", "K", "L",
            "M", "N", "O", "P", "Q", "R"
            );
    List<String> topCategories = Arrays.asList("C", "F");
    List<String> bottomCategories = Arrays.asList("M", "P", "R");
    Collections.sort(allCategories, new CategoryComparator(topCategories, bottomCategories));
public class CategoryComparator implements Comparator<String> {

    private static final int POSITIVE_SCORE = +1;
    private static final int NEGATIVE_SCORE = -1;
    private static final int TOP_SCORE_ADJUSTMENT = -2;
    private static final int BOTTOM_SCORE_ADJUSTMENT = +2;

    private Set<String> topCategories;
    private Set<String> bottomCategories;

    public CategoryComparator(Collection<String> topCategories, Collection<String> bottomCategories) {
        this.topCategories = new HashSet<>(topCategories);
        this.bottomCategories = new HashSet<>(bottomCategories);
    }

    @Override
    public int compare(String o1, String o2) {
        return normalizeScore(o1.compareTo(o2)) + ajustScoreForCategory(o1) - ajustScoreForCategory(o2);
    }

    private int normalizeScore(int score) {
        if (score < 0) {
            return NEGATIVE_SCORE;
        }
        if (score > 0) {
            return POSITIVE_SCORE;
        }
        return 0;
    }

    private int ajustScoreForCategory(String value) {
        int scoreAdjustment = 0;
        if (topCategories.contains(value)) {
            scoreAdjustment += TOP_SCORE_ADJUSTMENT;
        }
        if (bottomCategories.contains(value)) {
            scoreAdjustment += BOTTOM_SCORE_ADJUSTMENT;
        }
        return scoreAdjustment;
    }
}

Context

StackExchange Code Review Q#79847, answer score: 4

Revisions (0)

No revisions yet.