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