Sort ArrayList in a better way 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&lt;String&gt; categories = new ArrayList&lt;&gt;();
    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&lt;String&gt; categories) {
    List&lt;String&gt; topCategories = new ArrayList&lt;&gt;();
    List&lt;String&gt; bottomCategories = new ArrayList&lt;&gt;();

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

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

    categories.removeAll(topCategories);
    categories.removeAll(bottomCategories);

    Collections.sort(categories, new Comparator&lt;String&gt;() {

        @Override
        public int compare(String lhs, String rhs) {
            return lhs.compareTo(rhs);
        }
    });

    categories.addAll(0, topCategories);
    categories.addAll(categories.size(), bottomCategories);
}


And the output is:




Category NAME C
Category NAME F
Category NAME A
Category NAME B
Category NAME D
Category NAME E
Category NAME G
Category NAME H
Category NAME I
Category NAME J
Category NAME K
Category NAME L
Category NAME N
Category NAME O
Category NAME Q
Category NAME R
Category NAME M
Category NAME P
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&lt;String&gt; allCategories = Arrays.asList(
            "A", "B", "C", "D", "E", "F",
            "G", "H", "I", "J", "K", "L",
            "M", "N", "O", "P", "Q", "R"
            );
    List&lt;String&gt; topCategories = Arrays.asList("C", "F");
    List&lt;String&gt; 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&lt;String&gt; {

    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&lt;String&gt; topCategories;
    private Set&lt;String&gt; bottomCategories;

    public CategoryComparator(Collection&lt;String&gt; topCategories, Collection&lt;String&gt; bottomCategories) {
        this.topCategories = new HashSet&lt;&gt;(topCategories);
        this.bottomCategories = new HashSet&lt;&gt;(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 &lt; 0) {
            return NEGATIVE_SCORE;
        }
        if (score &gt; 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;
    }
}