How can I sort a list of clothing sizes (e.g. 4XL, S, 2XL)?

Build a comparator which does a lookup on your desired order:

Comparator<String> sizeOrder = Comparator.comparingInt(desiredOrder::indexOf);

where

desiredOrder = Arrays.asList("S", "M", "L", "XL", "2XL", "3XL", "4XL", "5XL", "6XL");

Then:

yourList.sort(sizeOrder);

If you want, you can build a Map<String, Integer> for the lookup:

Map<String, Integer> lookup =
    IntStream.range(0, desiredOrder.length())
        .boxed()
        .collect(Collectors.toMap(desiredOrder::get, i -> i));

And then do:

Comparator<String> sizeOrder = Comparator.comparing(lookup::get);

I'm not convinced that this will be any more performant than using List.indexOf, because the desiredOrder list is so small.

As with everything performance-related: use the one which you find most readable; profile if you think this is a performance bottleneck, and only then try alternatives.


A general approach would focus on the pattern behind the size strings rather than just accom­modating the sample input. You have a fundamental direction denoted by S, M, or L and optional modifiers before it (unless M) altering the magnitude.

static Pattern SIZE_PATTERN=Pattern.compile("((\\d+)?X)?[LS]|M", Pattern.CASE_INSENSITIVE);
static int numerical(String size) {
    Matcher m = SIZE_PATTERN.matcher(size);
    if(!m.matches()) throw new IllegalArgumentException(size);
    char c = size.charAt(m.end()-1);
    int n = c == 'S'? -1: c == 'L'? 1: 0;
    if(m.start(1)>=0) n *= 2;
    if(m.start(2)>=0) n *= Integer.parseInt(m.group(2));
    return n;
}

Then, you can sort a list of sizes like

List<String> sizes = Arrays.asList("2XL", "5XL", "M", "S", "6XL", "XS", "3XS", "L", "XL");
sizes.sort(Comparator.comparing(Q48298432::numerical));
System.out.print(sizes.toString());

where Q48298432 should be replaced with the name of the class containing the numerical method.


An alternative using the probably more efficient and certainly clearer enum route.

// Sizes in sort order.
enum Size {
    SMALL("S"),
    MEDIUM("M"),
    LARGE("L"),
    EXTRA_LARGE("XL"),
    EXTRA2_LARGE("2XL"),
    EXTRA3_LARGE("3XL"),
    EXTRA4_LARGE("4XL"),
    EXTRA5_LARGE("5XL"),
    EXTRA6_LARGE("6XL");
    private final String indicator;

    Size(String indicator) {
        this.indicator = indicator;
    }

    static final Map<String,Size> lookup = Arrays.asList(values()).stream()
            .collect(Collectors.toMap(
                    // Key is the indicator.
                    s -> s.indicator,
                    // Value is the size.
                    s-> s));

    public static Size lookup(String s) {
        return lookup.get(s.toUpperCase());
    }

    // Could be improved to handle failed lookups. 
    public static final Comparator<String> sizeOrder = (o1, o2) -> lookup(o1).ordinal() - lookup(o2).ordinal();
}

public void test(String[] args) {
    List<String> test = Arrays.asList("S","6XL", "L");
    Collections.sort(test, Size.sizeOrder);
    System.out.println(test);
}

Tags:

Java

Java 8